2 ** Copyright 2002-2006, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
6 #include <kernel/vfs.h>
7 #include <kernel/heap.h>
8 #include <kernel/khash.h>
9 #include <kernel/debug.h>
10 #include <kernel/lock.h>
11 #include <kernel/sem.h>
12 #include <kernel/vm.h>
13 #include <kernel/net/misc.h>
15 #include <newos/net.h>
28 #define TRACE(x...) dprintf(x)
33 static int nfs_getattr(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_attrstat
*attrstat
);
36 static void dump_fhandle(const fhandle
*handle
)
40 for(i
=0; i
<sizeof(fhandle
); i
++)
41 dprintf("%02x", ((const uint8
*)handle
)[i
]);
45 static nfs_vnode
*new_vnode_struct(nfs_fs
*fs
)
49 v
= (nfs_vnode
*)kmalloc(sizeof(nfs_vnode
));
53 if (mutex_init(&v
->lock
, "nfs vnode lock") < 0) {
64 static void destroy_vnode_struct(nfs_vnode
*v
)
66 mutex_destroy(&v
->lock
);
70 /* ghetto x.x.x.x:/path parsing code */
71 static int parse_mount(const char *mount
, char *address
, int address_len
, char *server_path
, int path_len
)
76 for(a
= 0; mount
[a
] != 0 && isspace(mount
[a
]); a
++)
82 for(b
= a
; mount
[b
] != 0 && mount
[b
] != ':'; b
++)
87 // copy the address out
88 memcpy(address
, &mount
[a
], b
- a
);
92 strcpy(server_path
, &mount
[b
+1]);
97 static int nfs_handle_hash_compare(void *a
, const void *key
)
99 struct nfs_vnode
*v
= (struct nfs_vnode
*)a
;
100 fhandle
*handle
= (fhandle
*)key
;
102 return memcmp(&v
->nfs_handle
, handle
, sizeof(*handle
));
105 static unsigned int nfs_handle_hash(void *a
, const void *key
, unsigned int range
)
112 hashit
= (fhandle
*)key
;
114 hashit
= (fhandle
*)&((nfs_vnode
*)a
)->nfs_handle
;
117 dprintf("nfs_handle_hash: hashit ");
118 dump_fhandle(hashit
);
122 for (i
=0; i
< sizeof(hashit
->handle
) / sizeof(unsigned int); i
++) {
123 hash
+= ((unsigned int *)hashit
->handle
)[i
];
130 dprintf(" hash 0x%x\n", hash
);
136 static int parse_ipv4_addr_str(ipv4_addr
*ip_addr
, char *ip_addr_string
)
142 // walk through the first number
145 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
147 if(ip_addr_string
[b
] == 0)
148 return ERR_NOT_FOUND
;
149 ip_addr_string
[b
] = 0;
150 *ip_addr
= atoi(&ip_addr_string
[a
]) << 24;
155 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
157 if(ip_addr_string
[b
] == 0)
158 return ERR_NOT_FOUND
;
159 ip_addr_string
[b
] = 0;
160 *ip_addr
|= atoi(&ip_addr_string
[a
]) << 16;
165 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
167 if(ip_addr_string
[b
] == 0)
168 return ERR_NOT_FOUND
;
169 ip_addr_string
[b
] = 0;
170 *ip_addr
|= atoi(&ip_addr_string
[a
]) << 8;
175 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
177 ip_addr_string
[b
] = 0;
178 *ip_addr
|= atoi(&ip_addr_string
[a
]);
183 static int nfs_mount_fs(nfs_fs
*nfs
, const char *server_path
)
185 struct mount_args args
;
189 memset(&args
, sizeof(args
), 0);
190 strlcpy(args
.dirpath
, server_path
, sizeof(args
.dirpath
));
191 args
.len
= htonl(strlen(args
.dirpath
));
193 rpc_set_port(&nfs
->rpc
, nfs
->mount_port
);
195 err
= rpc_call(&nfs
->rpc
, MOUNTPROG
, MOUNTVERS
, MOUNTPROC_MNT
, &args
, ntohl(args
.len
) + 4, buf
, sizeof(buf
));
200 TRACE("nfs_mount_fs: have root fhandle: ");
201 dump_fhandle((fhandle
*)&buf
[4]);
204 // we should have the root handle now
205 memcpy(&nfs
->root_vnode
->nfs_handle
, &buf
[4], sizeof(nfs
->root_vnode
->nfs_handle
));
207 // set the rpc port to the nfs server
208 rpc_set_port(&nfs
->rpc
, nfs
->nfs_port
);
213 static int nfs_unmount_fs(nfs_fs
*nfs
)
215 struct mount_args args
;
218 memset(&args
, sizeof(args
), 0);
219 strlcpy(args
.dirpath
, nfs
->server_path
, sizeof(args
.dirpath
));
220 args
.len
= htonl(strlen(args
.dirpath
));
222 rpc_set_port(&nfs
->rpc
, nfs
->mount_port
);
224 err
= rpc_call(&nfs
->rpc
, MOUNTPROG
, MOUNTVERS
, MOUNTPROC_UMNT
, &args
, ntohl(args
.len
) + 4, NULL
, 0);
229 int nfs_mount(fs_cookie
*fs
, fs_id id
, const char *device
, void *args
, vnode_id
*root_vnid
)
233 char ip_addr_str
[128];
236 TRACE("nfs_mount: fsid 0x%x, device '%s'\n", id
, device
);
238 /* create the fs structure */
239 nfs
= kmalloc(sizeof(nfs_fs
));
244 memset(nfs
, 0, sizeof(nfs_fs
));
246 mutex_init(&nfs
->lock
, "nfs lock");
248 err
= parse_mount(device
, ip_addr_str
, sizeof(ip_addr_str
), nfs
->server_path
, sizeof(nfs
->server_path
));
250 err
= ERR_NET_BAD_ADDRESS
;
254 err
= parse_ipv4_addr_str(&ip_addr
, ip_addr_str
);
256 err
= ERR_NET_BAD_ADDRESS
;
261 nfs
->server_addr
.type
= ADDR_TYPE_IP
;
262 nfs
->server_addr
.len
= 4;
263 NETADDR_TO_IPV4(nfs
->server_addr
) = ip_addr
;
265 // set up the rpc state
266 rpc_init_state(&nfs
->rpc
);
267 rpc_open_socket(&nfs
->rpc
, &nfs
->server_addr
);
269 // look up the port numbers for mount and nfs
270 rpc_pmap_lookup(&nfs
->server_addr
, MOUNTPROG
, MOUNTVERS
, IP_PROT_UDP
, &nfs
->mount_port
);
271 rpc_pmap_lookup(&nfs
->server_addr
, NFSPROG
, NFSVERS
, IP_PROT_UDP
, &nfs
->nfs_port
);
273 nfs
->root_vnode
= new_vnode_struct(nfs
);
274 nfs
->root_vnode
->st
= STREAM_TYPE_DIR
;
276 // try to mount the filesystem
277 err
= nfs_mount_fs(nfs
, nfs
->server_path
);
281 // build the vnode hash table and stick the root vnode in it
282 nfs
->handle_hash
= hash_init(1024, offsetof(struct nfs_vnode
, hash_next
),
283 nfs_handle_hash_compare
,
285 if (!nfs
->handle_hash
) {
289 hash_insert(nfs
->handle_hash
, nfs
->root_vnode
);
292 *root_vnid
= VNODETOVNID(nfs
->root_vnode
);
297 destroy_vnode_struct(nfs
->root_vnode
);
298 rpc_destroy_state(&nfs
->rpc
);
300 mutex_destroy(&nfs
->lock
);
306 int nfs_unmount(fs_cookie fs
)
308 nfs_fs
*nfs
= (nfs_fs
*)fs
;
310 TRACE("nfs_unmount: fsid 0x%x\n", nfs
->id
);
312 // put_vnode on the root to release the ref to it
313 vfs_put_vnode(nfs
->id
, VNODETOVNID(nfs
->root_vnode
));
317 hash_uninit(nfs
->handle_hash
);
319 rpc_destroy_state(&nfs
->rpc
);
321 mutex_destroy(&nfs
->lock
);
327 int nfs_sync(fs_cookie fs
)
329 nfs_fs
*nfs
= (nfs_fs
*)fs
;
333 TRACE("nfs_sync: fsid 0x%x\n", nfs
->id
);
337 int nfs_lookup(fs_cookie fs
, fs_vnode _dir
, const char *name
, vnode_id
*id
)
339 nfs_fs
*nfs
= (nfs_fs
*)fs
;
340 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
343 TRACE("nfs_lookup: fsid 0x%x, dirvnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
345 mutex_lock(&dir
->lock
);
348 uint8 buf
[sizeof(nfs_diropargs
)];
349 nfs_diropargs
*args
= (nfs_diropargs
*)buf
;
350 nfs_diropres
*res
= (nfs_diropres
*)buf
;
351 int namelen
= min(MAXNAMLEN
, strlen(name
));
353 /* set up the args structure */
354 memcpy(&args
->dir
, &dir
->nfs_handle
, sizeof(args
->dir
));
356 args
->name
.len
= htonl(namelen
);
357 memcpy(args
->name
.name
, name
, namelen
);
359 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_LOOKUP
, args
, sizeof(nfs_diropargs
), buf
, sizeof(buf
));
365 /* see if the lookup was successful */
366 if(htonl(res
->status
) == NFS_OK
) {
371 /* successful lookup */
373 dprintf("nfs_lookup: result of lookup of '%s'\n", name
);
374 dprintf("\tfhandle: "); dump_fhandle(&res
->file
); dprintf("\n");
375 dprintf("\tsize: %d\n", ntohl(res
->attributes
.size
));
376 nfs_handle_hash(NULL
, &res
->file
, 1024);
379 /* see if the vnode already exists */
381 v
= hash_lookup(nfs
->handle_hash
, &res
->file
);
383 /* didn't find it, create a new one */
384 v
= new_vnode_struct(nfs
);
390 /* copy the file handle over */
391 memcpy(&v
->nfs_handle
, &res
->file
, sizeof(v
->nfs_handle
));
393 /* figure out the stream type from the return value and cache it */
394 switch(ntohl(res
->attributes
.ftype
)) {
396 v
->st
= STREAM_TYPE_FILE
;
399 v
->st
= STREAM_TYPE_DIR
;
405 /* add it to the handle -> vnode lookup table */
406 mutex_lock(&nfs
->lock
);
407 hash_insert(nfs
->handle_hash
, v
);
408 mutex_unlock(&nfs
->lock
);
412 /* request that the vfs layer look it up */
413 err
= vfs_get_vnode(nfs
->id
, VNODETOVNID(v
), (fs_vnode
*)(void *)&v2
);
416 mutex_lock(&nfs
->lock
);
417 hash_remove(nfs
->handle_hash
, v
);
418 mutex_unlock(&nfs
->lock
);
419 destroy_vnode_struct(v
);
427 *id
= VNODETOVNID(v
);
429 TRACE("nfs_lookup: '%s' not found\n", name
);
438 mutex_unlock(&dir
->lock
);
443 int nfs_getvnode(fs_cookie fs
, vnode_id id
, fs_vnode
*v
, bool r
)
445 nfs_fs
*nfs
= (nfs_fs
*)fs
;
449 TRACE("nfs_getvnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, id
);
451 *v
= VNIDTOVNODE(id
);
456 int nfs_putvnode(fs_cookie fs
, fs_vnode _v
, bool r
)
458 nfs_fs
*nfs
= (nfs_fs
*)fs
;
459 nfs_vnode
*v
= (nfs_vnode
*)_v
;
463 TRACE("nfs_putvnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
465 mutex_lock(&nfs
->lock
);
466 hash_remove(nfs
->handle_hash
, v
);
467 mutex_unlock(&nfs
->lock
);
468 destroy_vnode_struct(v
);
473 int nfs_removevnode(fs_cookie fs
, fs_vnode _v
, bool r
)
475 nfs_fs
*nfs
= (nfs_fs
*)fs
;
476 nfs_vnode
*v
= (nfs_vnode
*)_v
;
480 TRACE("nfs_removevnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
482 return ERR_UNIMPLEMENTED
;
485 static int nfs_opendir(fs_cookie _fs
, fs_vnode _v
, dir_cookie
*_cookie
)
487 struct nfs_vnode
*v
= (struct nfs_vnode
*)_v
;
488 struct nfs_cookie
*cookie
;
491 TRACE("nfs_opendir: vnode %p\n", v
);
493 if(v
->st
!= STREAM_TYPE_DIR
)
494 return ERR_VFS_NOT_DIR
;
496 cookie
= kmalloc(sizeof(struct nfs_cookie
));
498 return ERR_NO_MEMORY
;
501 cookie
->u
.dir
.nfscookie
= 0;
502 cookie
->u
.dir
.at_end
= false;
509 static int nfs_closedir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
)
511 struct nfs_fs
*fs
= _fs
;
512 struct nfs_vnode
*v
= _v
;
513 struct nfs_cookie
*cookie
= _cookie
;
515 TOUCH(fs
);TOUCH(v
);TOUCH(cookie
);
517 TRACE("nfs_closedir: entry vnode %p, cookie %p\n", v
, cookie
);
519 if(v
->st
!= STREAM_TYPE_DIR
)
520 return ERR_VFS_NOT_DIR
;
528 static int nfs_rewinddir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
)
530 struct nfs_vnode
*v
= _v
;
531 struct nfs_cookie
*cookie
= _cookie
;
536 TRACE("nfs_rewinddir: vnode %p, cookie %p\n", v
, cookie
);
538 if(v
->st
!= STREAM_TYPE_DIR
)
539 return ERR_VFS_NOT_DIR
;
541 mutex_lock(&v
->lock
);
543 cookie
->u
.dir
.nfscookie
= 0;
544 cookie
->u
.dir
.at_end
= false;
546 mutex_unlock(&v
->lock
);
551 #define READDIR_BUF_SIZE (MAXNAMLEN + 64)
553 static ssize_t
_nfs_readdir(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_cookie
*cookie
, void *buf
, ssize_t len
)
555 uint8 abuf
[READDIR_BUF_SIZE
];
556 nfs_readdirargs
*args
= (nfs_readdirargs
*)abuf
;
557 nfs_readdirres
*res
= (nfs_readdirres
*)abuf
;
563 return ERR_VFS_INSUFFICIENT_BUF
; // XXX not quite accurate
565 /* see if we've already hit the end */
566 if(cookie
->u
.dir
.at_end
)
569 /* put together the message */
570 memcpy(&args
->dir
, &v
->nfs_handle
, sizeof(args
->dir
));
571 args
->cookie
= cookie
->u
.dir
.nfscookie
;
572 args
->count
= htonl(min(len
, READDIR_BUF_SIZE
));
574 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_READDIR
, args
, sizeof(*args
), abuf
, sizeof(abuf
));
579 if(ntohl(res
->status
) != NFS_OK
)
582 /* walk into the buffer, looking for the first entry */
583 if(ntohl(res
->data
[0]) == 0) {
585 cookie
->u
.dir
.at_end
= true;
588 i
= ntohl(res
->data
[0]);
590 /* copy the data out of the first entry */
591 strlcpy(buf
, (char const *)&res
->data
[i
+ 2], ntohl(res
->data
[i
+ 1]) + 1);
593 namelen
= ROUNDUP(ntohl(res
->data
[i
+ 1]), 4);
595 /* update the cookie */
596 cookie
->u
.dir
.nfscookie
= res
->data
[i
+ namelen
/ 4 + 2];
598 return ntohl(res
->data
[i
+ 1]);
601 static int nfs_readdir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
, void *buf
, size_t len
)
603 struct nfs_fs
*fs
= _fs
;
604 struct nfs_vnode
*v
= _v
;
605 struct nfs_cookie
*cookie
= _cookie
;
610 TRACE("nfs_readdir: vnode %p, cookie %p, len 0x%x\n", v
, cookie
, len
);
612 if(v
->st
!= STREAM_TYPE_DIR
)
613 return ERR_VFS_NOT_DIR
;
615 mutex_lock(&v
->lock
);
617 err
= _nfs_readdir(fs
, v
, cookie
, buf
, len
);
619 mutex_unlock(&v
->lock
);
624 int nfs_open(fs_cookie fs
, fs_vnode _v
, file_cookie
*_cookie
, int oflags
)
626 nfs_fs
*nfs
= (nfs_fs
*)fs
;
627 nfs_vnode
*v
= (nfs_vnode
*)_v
;
633 TRACE("nfs_open: fsid 0x%x, vnid 0x%Lx, oflags 0x%x\n", nfs
->id
, VNODETOVNID(v
), oflags
);
635 if(v
->st
== STREAM_TYPE_DIR
) {
636 err
= ERR_VFS_IS_DIR
;
640 cookie
= kmalloc(sizeof(nfs_cookie
));
647 cookie
->u
.file
.pos
= 0;
648 cookie
->u
.file
.oflags
= oflags
;
650 *_cookie
= (file_cookie
)cookie
;
657 int nfs_close(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
)
659 nfs_fs
*nfs
= (nfs_fs
*)fs
;
660 nfs_vnode
*v
= (nfs_vnode
*)_v
;
664 TRACE("nfs_close: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
666 if(v
->st
== STREAM_TYPE_DIR
)
667 return ERR_VFS_IS_DIR
;
672 int nfs_freecookie(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
)
674 nfs_fs
*nfs
= (nfs_fs
*)fs
;
675 nfs_vnode
*v
= (nfs_vnode
*)_v
;
676 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
680 TRACE("nfs_freecookie: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
682 if(v
->st
== STREAM_TYPE_DIR
)
683 return ERR_VFS_IS_DIR
;
690 int nfs_fsync(fs_cookie fs
, fs_vnode _v
)
692 nfs_fs
*nfs
= (nfs_fs
*)fs
;
693 nfs_vnode
*v
= (nfs_vnode
*)_v
;
697 TRACE("nfs_fsync: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
702 #define READ_BUF_SIZE 1024
704 static ssize_t
nfs_readfile(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_cookie
*cookie
, void *buf
, off_t pos
, ssize_t len
, bool updatecookiepos
)
706 uint8 abuf
[4 + sizeof(nfs_fattr
) + READ_BUF_SIZE
];
707 nfs_readargs
*args
= (nfs_readargs
*)abuf
;
708 nfs_readres
*res
= (nfs_readres
*)abuf
;
710 ssize_t total_read
= 0;
712 TRACE("nfs_readfile: v %p, buf %p, pos %Ld, len %d\n", v
, buf
, pos
, len
);
716 pos
= cookie
->u
.file
.pos
;
717 /* can't do more than 32-bit offsets right now */
720 /* negative or zero length means nothing */
725 ssize_t to_read
= min(len
, READ_BUF_SIZE
);
727 /* put together the message */
728 memcpy(&args
->file
, &v
->nfs_handle
, sizeof(args
->file
));
729 args
->offset
= htonl(pos
);
730 args
->count
= htonl(to_read
);
731 args
->totalcount
= 0; // unused
733 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_READ
, args
, sizeof(*args
), abuf
, sizeof(abuf
));
738 if(ntohl(res
->status
) != NFS_OK
)
741 /* see how much we read */
742 err
= user_memcpy((uint8
*)buf
+ total_read
, res
->data
, ntohl(res
->len
));
744 total_read
= err
; // bad user give me bad buffer
748 pos
+= ntohl(res
->len
);
749 len
-= ntohl(res
->len
);
750 total_read
+= ntohl(res
->len
);
752 /* short read, we're done */
753 if((ssize_t
)ntohl(res
->len
) != to_read
)
758 cookie
->u
.file
.pos
= pos
;
763 ssize_t
nfs_read(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, void *buf
, off_t pos
, ssize_t len
)
765 nfs_fs
*nfs
= (nfs_fs
*)fs
;
766 nfs_vnode
*v
= (nfs_vnode
*)_v
;
767 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
770 TRACE("nfs_read: fsid 0x%x, vnid 0x%Lx, buf %p, pos 0x%Lx, len %ld\n", nfs
->id
, VNODETOVNID(v
), buf
, pos
, len
);
772 if(v
->st
== STREAM_TYPE_DIR
)
773 return ERR_VFS_IS_DIR
;
775 mutex_lock(&v
->lock
);
777 err
= nfs_readfile(nfs
, v
, cookie
, buf
, pos
, len
, true);
779 mutex_unlock(&v
->lock
);
784 #define WRITE_BUF_SIZE 1024
786 static ssize_t
nfs_writefile(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_cookie
*cookie
, const void *buf
, off_t pos
, ssize_t len
, bool updatecookiepos
)
788 uint8 abuf
[sizeof(nfs_writeargs
) + WRITE_BUF_SIZE
];
789 nfs_writeargs
*args
= (nfs_writeargs
*)abuf
;
790 nfs_attrstat
*res
= (nfs_attrstat
*)abuf
;
792 ssize_t total_written
= 0;
796 pos
= cookie
->u
.file
.pos
;
797 /* can't do more than 32-bit offsets right now */
800 /* negative or zero length means nothing */
805 ssize_t to_write
= min(len
, WRITE_BUF_SIZE
);
807 /* put together the message */
808 memcpy(&args
->file
, &v
->nfs_handle
, sizeof(args
->file
));
809 args
->beginoffset
= 0; // unused
810 args
->offset
= htonl(pos
);
811 args
->totalcount
= 0; // unused
812 args
->len
= htonl(to_write
);
813 err
= user_memcpy(args
->data
, (const uint8
*)buf
+ total_written
, to_write
);
819 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_WRITE
, args
, sizeof(*args
) + to_write
, abuf
, sizeof(abuf
));
824 if(ntohl(res
->status
) != NFS_OK
)
829 total_written
+= to_write
;
833 cookie
->u
.file
.pos
= pos
;
835 return total_written
;
838 ssize_t
nfs_write(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, const void *buf
, off_t pos
, ssize_t len
)
840 nfs_fs
*nfs
= (nfs_fs
*)fs
;
841 nfs_vnode
*v
= (nfs_vnode
*)_v
;
842 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
845 TRACE("nfs_write: fsid 0x%x, vnid 0x%Lx, buf %p, pos 0x%Lx, len %ld\n", nfs
->id
, VNODETOVNID(v
), buf
, pos
, len
);
847 mutex_lock(&v
->lock
);
850 case STREAM_TYPE_FILE
:
851 err
= nfs_writefile(nfs
, v
, cookie
, buf
, pos
, len
, true);
853 case STREAM_TYPE_DIR
:
854 err
= ERR_NOT_ALLOWED
;
860 mutex_unlock(&v
->lock
);
865 int nfs_seek(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, off_t pos
, seek_type st
)
867 nfs_fs
*nfs
= (nfs_fs
*)fs
;
868 nfs_vnode
*v
= (nfs_vnode
*)_v
;
869 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
871 nfs_attrstat attrstat
;
874 TRACE("nfs_seek: fsid 0x%x, vnid 0x%Lx, pos 0x%Lx, seek_type %d\n", nfs
->id
, VNODETOVNID(v
), pos
, st
);
876 if(v
->st
== STREAM_TYPE_DIR
)
877 return ERR_VFS_IS_DIR
;
879 mutex_lock(&v
->lock
);
881 err
= nfs_getattr(nfs
, v
, &attrstat
);
885 file_len
= ntohl(attrstat
.attributes
.size
);
893 cookie
->u
.file
.pos
= pos
;
896 if(pos
+ cookie
->u
.file
.pos
> file_len
)
897 cookie
->u
.file
.pos
= file_len
;
898 else if(pos
+ cookie
->u
.file
.pos
< 0)
899 cookie
->u
.file
.pos
= 0;
901 cookie
->u
.file
.pos
+= pos
;
905 cookie
->u
.file
.pos
= file_len
;
906 else if(pos
+ file_len
< 0)
907 cookie
->u
.file
.pos
= 0;
909 cookie
->u
.file
.pos
= pos
+ file_len
;
912 err
= ERR_INVALID_ARGS
;
916 mutex_unlock(&v
->lock
);
921 int nfs_ioctl(fs_cookie fs
, fs_vnode _v
, file_cookie cookie
, int op
, void *buf
, size_t len
)
923 nfs_fs
*nfs
= (nfs_fs
*)fs
;
924 nfs_vnode
*v
= (nfs_vnode
*)_v
;
928 TRACE("nfs_ioctl: fsid 0x%x, vnid 0x%Lx, op %d, buf %p, len %ld\n", nfs
->id
, VNODETOVNID(v
), op
, buf
, len
);
930 return ERR_UNIMPLEMENTED
;
933 int nfs_canpage(fs_cookie fs
, fs_vnode _v
)
935 nfs_fs
*nfs
= (nfs_fs
*)fs
;
936 nfs_vnode
*v
= (nfs_vnode
*)_v
;
940 TRACE("nfs_canpage: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
942 if(v
->st
== STREAM_TYPE_FILE
)
948 ssize_t
nfs_readpage(fs_cookie fs
, fs_vnode _v
, iovecs
*vecs
, off_t pos
)
950 nfs_fs
*nfs
= (nfs_fs
*)fs
;
951 nfs_vnode
*v
= (nfs_vnode
*)_v
;
953 ssize_t readfile_return
;
954 ssize_t total_bytes_read
= 0;
958 TRACE("nfs_readpage: fsid 0x%x, vnid 0x%Lx, vecs %p, pos 0x%Lx\n", nfs
->id
, VNODETOVNID(v
), vecs
, pos
);
960 if(v
->st
== STREAM_TYPE_DIR
)
961 return ERR_VFS_IS_DIR
;
963 mutex_lock(&v
->lock
);
965 for (i
=0; i
< vecs
->num
; i
++) {
966 readfile_return
= nfs_readfile(nfs
, v
, NULL
, vecs
->vec
[i
].start
, pos
, vecs
->vec
[i
].len
, false);
967 TRACE("nfs_readpage: nfs_readfile returns %d\n", readfile_return
);
968 if (readfile_return
< 0)
971 pos
+= readfile_return
;
972 total_bytes_read
+= readfile_return
;
974 if ((size_t)readfile_return
< vecs
->vec
[i
].len
) {
975 /* we have hit the end of file, zero out the rest */
976 for (; i
< vecs
->num
; i
++) {
977 memset(vecs
->vec
[i
].start
+ readfile_return
, 0, vecs
->vec
[i
].len
- readfile_return
);
978 total_bytes_read
+= vecs
->vec
[i
].len
- readfile_return
;
980 readfile_return
= 0; // after the first pass, wipe out entire pages
986 mutex_unlock(&v
->lock
);
988 return total_bytes_read
;
991 ssize_t
nfs_writepage(fs_cookie fs
, fs_vnode _v
, iovecs
*vecs
, off_t pos
)
993 nfs_fs
*nfs
= (nfs_fs
*)fs
;
994 nfs_vnode
*v
= (nfs_vnode
*)_v
;
998 TRACE("nfs_writepage: fsid 0x%x, vnid 0x%Lx, vecs %p, pos 0x%Lx\n", nfs
->id
, VNODETOVNID(v
), vecs
, pos
);
1000 if(v
->st
== STREAM_TYPE_DIR
)
1001 return ERR_VFS_IS_DIR
;
1003 return ERR_UNIMPLEMENTED
;
1006 int nfs_create(fs_cookie fs
, fs_vnode _dir
, const char *name
, void *create_args
, vnode_id
*new_vnid
)
1008 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1009 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
1011 TOUCH(nfs
);TOUCH(dir
);
1013 TRACE("nfs_create: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1015 return ERR_UNIMPLEMENTED
;
1018 int nfs_unlink(fs_cookie fs
, fs_vnode _dir
, const char *name
)
1020 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1021 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
1023 TOUCH(nfs
);TOUCH(dir
);
1025 TRACE("nfs_unlink: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1027 return ERR_UNIMPLEMENTED
;
1030 int nfs_rename(fs_cookie fs
, fs_vnode _olddir
, const char *oldname
, fs_vnode _newdir
, const char *newname
)
1032 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1033 nfs_vnode
*olddir
= (nfs_vnode
*)_olddir
;
1034 nfs_vnode
*newdir
= (nfs_vnode
*)_newdir
;
1036 TOUCH(nfs
);TOUCH(olddir
);TOUCH(newdir
);
1038 TRACE("nfs_rename: fsid 0x%x, vnid 0x%Lx, oldname '%s', newdir 0x%Lx, newname '%s'\n", nfs
->id
, VNODETOVNID(olddir
), oldname
, VNODETOVNID(newdir
), newname
);
1040 return ERR_UNIMPLEMENTED
;
1043 int nfs_mkdir(fs_cookie _fs
, fs_vnode _base_dir
, const char *name
)
1045 nfs_fs
*nfs
= (nfs_fs
*)_fs
;
1046 nfs_vnode
*dir
= (nfs_vnode
*)_base_dir
;
1048 TOUCH(nfs
);TOUCH(dir
);
1050 TRACE("nfs_mkdir: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1052 return ERR_UNIMPLEMENTED
;
1055 int nfs_rmdir(fs_cookie _fs
, fs_vnode _base_dir
, const char *name
)
1057 nfs_fs
*nfs
= (nfs_fs
*)_fs
;
1058 nfs_vnode
*dir
= (nfs_vnode
*)_base_dir
;
1060 TOUCH(nfs
);TOUCH(dir
);
1062 TRACE("nfs_rmdir: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1064 return ERR_UNIMPLEMENTED
;
1067 static int nfs_getattr(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_attrstat
*attrstat
)
1069 return rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_GETATTR
, &v
->nfs_handle
, sizeof(v
->nfs_handle
), attrstat
, sizeof(nfs_attrstat
));
1072 int nfs_rstat(fs_cookie fs
, fs_vnode _v
, struct file_stat
*stat
)
1074 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1075 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1076 nfs_attrstat attrstat
;
1079 TRACE("nfs_rstat: fsid 0x%x, vnid 0x%Lx, stat %p\n", nfs
->id
, VNODETOVNID(v
), stat
);
1081 mutex_lock(&v
->lock
);
1083 err
= nfs_getattr(nfs
, v
, &attrstat
);
1087 if(ntohl(attrstat
.status
) != NFS_OK
) {
1092 /* copy the stat over from the nfs attrstat */
1093 stat
->vnid
= VNODETOVNID(v
);
1094 stat
->size
= ntohl(attrstat
.attributes
.size
);
1095 switch(ntohl(attrstat
.attributes
.ftype
)) {
1097 stat
->type
= STREAM_TYPE_FILE
;
1100 stat
->type
= STREAM_TYPE_DIR
;
1103 stat
->type
= STREAM_TYPE_DEVICE
; // XXX should have unknown type
1110 mutex_unlock(&v
->lock
);
1115 int nfs_wstat(fs_cookie fs
, fs_vnode _v
, struct file_stat
*stat
, int stat_mask
)
1117 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1118 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1120 TOUCH(nfs
);TOUCH(v
);
1122 TRACE("nfs_wstat: fsid 0x%x, vnid 0x%Lx, stat %p, stat_mask 0x%x\n", nfs
->id
, VNODETOVNID(v
), stat
, stat_mask
);
1124 return ERR_UNIMPLEMENTED
;
1127 static struct fs_calls nfs_calls
= {
1168 int fs_bootstrap(void);
1169 int fs_bootstrap(void)
1171 dprintf("bootstrap_nfs: entry\n");
1172 return vfs_register_filesystem("nfs", &nfs_calls
);