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
, uint8
*attrstatbuf
, nfs_attrstat
*attrstat
);
36 static void dump_fhandle(const nfs_fhandle
*handle
)
40 for(i
=0; i
<sizeof(nfs_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 nfs_fhandle
*handle
= (nfs_fhandle
*)key
;
102 return memcmp(&v
->nfs_handle
, handle
, sizeof(nfs_fhandle
));
105 static unsigned int nfs_handle_hash(void *a
, const void *key
, unsigned int range
)
107 const nfs_fhandle
*hashit
;
112 hashit
= (const nfs_fhandle
*)key
;
114 hashit
= (const nfs_fhandle
*)&((nfs_vnode
*)a
)->nfs_handle
;
117 dprintf("nfs_handle_hash: hashit ");
118 dump_fhandle(hashit
);
122 for (i
=0; i
< sizeof(*hashit
) / sizeof(unsigned int); i
++) {
123 hash
+= ((unsigned int *)hashit
)[i
];
130 dprintf(" hash 0x%x\n", hash
);
136 static int nfs_status_to_error(nfs_status status
)
142 return ERR_PERMISSION_DENIED
;
144 return ERR_VFS_PATH_NOT_FOUND
;
148 return ERR_NOT_FOUND
;
150 return ERR_PERMISSION_DENIED
;
152 return ERR_VFS_ALREADY_EXISTS
;
154 return ERR_NOT_FOUND
;
156 return ERR_VFS_NOT_DIR
;
158 return ERR_VFS_IS_DIR
;
162 return ERR_VFS_OUT_OF_SPACE
;
164 return ERR_VFS_READONLY_FS
;
165 case NFSERR_NAMETOOLONG
:
166 return ERR_VFS_PATH_TOO_LONG
;
167 case NFSERR_NOTEMPTY
:
168 return ERR_VFS_DIR_NOT_EMPTY
;
170 return ERR_VFS_EXCEEDED_QUOTA
;
172 return ERR_INVALID_HANDLE
;
178 static int parse_ipv4_addr_str(ipv4_addr
*ip_addr
, char *ip_addr_string
)
184 // walk through the first number
187 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
189 if(ip_addr_string
[b
] == 0)
190 return ERR_NOT_FOUND
;
191 ip_addr_string
[b
] = 0;
192 *ip_addr
= atoi(&ip_addr_string
[a
]) << 24;
197 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
199 if(ip_addr_string
[b
] == 0)
200 return ERR_NOT_FOUND
;
201 ip_addr_string
[b
] = 0;
202 *ip_addr
|= atoi(&ip_addr_string
[a
]) << 16;
207 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
209 if(ip_addr_string
[b
] == 0)
210 return ERR_NOT_FOUND
;
211 ip_addr_string
[b
] = 0;
212 *ip_addr
|= atoi(&ip_addr_string
[a
]) << 8;
217 for(; ip_addr_string
[b
] != 0 && ip_addr_string
[b
] != '.'; b
++)
219 ip_addr_string
[b
] = 0;
220 *ip_addr
|= atoi(&ip_addr_string
[a
]);
225 static int nfs_mount_fs(nfs_fs
*nfs
, const char *server_path
)
233 rpc_set_port(&nfs
->rpc
, nfs
->mount_port
);
235 args
.dirpath
= server_path
;
236 arglen
= nfs_pack_mountargs(sendbuf
, &args
);
238 err
= rpc_call(&nfs
->rpc
, MOUNTPROG
, MOUNTVERS
, MOUNTPROC_MNT
, sendbuf
, arglen
, buf
, sizeof(buf
));
243 TRACE("nfs_mount_fs: have root fhandle: ");
244 dump_fhandle((const nfs_fhandle
*)&buf
[4]);
247 // we should have the root handle now
248 memcpy(&nfs
->root_vnode
->nfs_handle
, &buf
[4], sizeof(nfs
->root_vnode
->nfs_handle
));
250 // set the rpc port to the nfs server
251 rpc_set_port(&nfs
->rpc
, nfs
->nfs_port
);
256 static int nfs_unmount_fs(nfs_fs
*nfs
)
263 rpc_set_port(&nfs
->rpc
, nfs
->mount_port
);
265 args
.dirpath
= nfs
->server_path
;
266 arglen
= nfs_pack_mountargs(sendbuf
, &args
);
268 err
= rpc_call(&nfs
->rpc
, MOUNTPROG
, MOUNTVERS
, MOUNTPROC_UMNT
, sendbuf
, arglen
, NULL
, 0);
273 int nfs_mount(fs_cookie
*fs
, fs_id id
, const char *device
, void *args
, vnode_id
*root_vnid
)
277 char ip_addr_str
[128];
280 TRACE("nfs_mount: fsid 0x%x, device '%s'\n", id
, device
);
282 /* create the fs structure */
283 nfs
= kmalloc(sizeof(nfs_fs
));
288 memset(nfs
, 0, sizeof(nfs_fs
));
290 mutex_init(&nfs
->lock
, "nfs lock");
292 err
= parse_mount(device
, ip_addr_str
, sizeof(ip_addr_str
), nfs
->server_path
, sizeof(nfs
->server_path
));
294 err
= ERR_NET_BAD_ADDRESS
;
298 err
= parse_ipv4_addr_str(&ip_addr
, ip_addr_str
);
300 err
= ERR_NET_BAD_ADDRESS
;
305 nfs
->server_addr
.type
= ADDR_TYPE_IP
;
306 nfs
->server_addr
.len
= 4;
307 NETADDR_TO_IPV4(nfs
->server_addr
) = ip_addr
;
309 // set up the rpc state
310 rpc_init_state(&nfs
->rpc
);
311 rpc_open_socket(&nfs
->rpc
, &nfs
->server_addr
);
313 // look up the port numbers for mount and nfs
314 rpc_pmap_lookup(&nfs
->server_addr
, MOUNTPROG
, MOUNTVERS
, IP_PROT_UDP
, &nfs
->mount_port
);
315 rpc_pmap_lookup(&nfs
->server_addr
, NFSPROG
, NFSVERS
, IP_PROT_UDP
, &nfs
->nfs_port
);
317 nfs
->root_vnode
= new_vnode_struct(nfs
);
318 nfs
->root_vnode
->st
= STREAM_TYPE_DIR
;
320 // try to mount the filesystem
321 err
= nfs_mount_fs(nfs
, nfs
->server_path
);
325 // build the vnode hash table and stick the root vnode in it
326 nfs
->handle_hash
= hash_init(1024, offsetof(struct nfs_vnode
, hash_next
),
327 nfs_handle_hash_compare
,
329 if (!nfs
->handle_hash
) {
333 hash_insert(nfs
->handle_hash
, nfs
->root_vnode
);
336 *root_vnid
= VNODETOVNID(nfs
->root_vnode
);
341 destroy_vnode_struct(nfs
->root_vnode
);
342 rpc_destroy_state(&nfs
->rpc
);
344 mutex_destroy(&nfs
->lock
);
350 int nfs_unmount(fs_cookie fs
)
352 nfs_fs
*nfs
= (nfs_fs
*)fs
;
354 TRACE("nfs_unmount: fsid 0x%x\n", nfs
->id
);
356 // put_vnode on the root to release the ref to it
357 vfs_put_vnode(nfs
->id
, VNODETOVNID(nfs
->root_vnode
));
361 hash_uninit(nfs
->handle_hash
);
363 rpc_destroy_state(&nfs
->rpc
);
365 mutex_destroy(&nfs
->lock
);
371 int nfs_sync(fs_cookie fs
)
373 nfs_fs
*nfs
= (nfs_fs
*)fs
;
377 TRACE("nfs_sync: fsid 0x%x\n", nfs
->id
);
381 int nfs_lookup(fs_cookie fs
, fs_vnode _dir
, const char *name
, vnode_id
*id
)
383 nfs_fs
*nfs
= (nfs_fs
*)fs
;
384 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
387 TRACE("nfs_lookup: fsid 0x%x, dirvnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
389 mutex_lock(&dir
->lock
);
392 uint8 sendbuf
[NFS_DIROPARGS_MAXLEN
];
396 uint8 resbuf
[NFS_DIROPRES_MAXLEN
];
399 /* set up the args structure */
400 args
.dir
= &dir
->nfs_handle
;
401 args
.name
.name
= name
;
402 arglen
= nfs_pack_diropargs(sendbuf
, &args
);
404 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_LOOKUP
, sendbuf
, arglen
, resbuf
, sizeof(resbuf
));
410 nfs_unpack_diropres(resbuf
, &res
);
412 /* see if the lookup was successful */
413 if(res
.status
== NFS_OK
) {
418 /* successful lookup */
420 dprintf("nfs_lookup: result of lookup of '%s'\n", name
);
421 dprintf("\tfhandle: "); dump_fhandle(res
.file
); dprintf("\n");
422 dprintf("\tsize: %d\n", res
.attributes
->size
);
423 nfs_handle_hash(NULL
, res
.file
, 1024);
426 /* see if the vnode already exists */
428 v
= hash_lookup(nfs
->handle_hash
, res
.file
);
430 /* didn't find it, create a new one */
431 v
= new_vnode_struct(nfs
);
437 /* copy the file handle over */
438 memcpy(&v
->nfs_handle
, res
.file
, sizeof(v
->nfs_handle
));
440 /* figure out the stream type from the return value and cache it */
441 switch(res
.attributes
->ftype
) {
443 v
->st
= STREAM_TYPE_FILE
;
446 v
->st
= STREAM_TYPE_DIR
;
452 /* add it to the handle -> vnode lookup table */
453 mutex_lock(&nfs
->lock
);
454 hash_insert(nfs
->handle_hash
, v
);
455 mutex_unlock(&nfs
->lock
);
459 /* request that the vfs layer look it up */
460 err
= vfs_get_vnode(nfs
->id
, VNODETOVNID(v
), (fs_vnode
*)(void *)&v2
);
463 mutex_lock(&nfs
->lock
);
464 hash_remove(nfs
->handle_hash
, v
);
465 mutex_unlock(&nfs
->lock
);
466 destroy_vnode_struct(v
);
474 *id
= VNODETOVNID(v
);
476 TRACE("nfs_lookup: '%s' not found\n", name
);
485 mutex_unlock(&dir
->lock
);
490 int nfs_getvnode(fs_cookie fs
, vnode_id id
, fs_vnode
*v
, bool r
)
492 nfs_fs
*nfs
= (nfs_fs
*)fs
;
496 TRACE("nfs_getvnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, id
);
498 *v
= VNIDTOVNODE(id
);
503 int nfs_putvnode(fs_cookie fs
, fs_vnode _v
, bool r
)
505 nfs_fs
*nfs
= (nfs_fs
*)fs
;
506 nfs_vnode
*v
= (nfs_vnode
*)_v
;
510 TRACE("nfs_putvnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
512 mutex_lock(&nfs
->lock
);
513 hash_remove(nfs
->handle_hash
, v
);
514 mutex_unlock(&nfs
->lock
);
515 destroy_vnode_struct(v
);
520 int nfs_removevnode(fs_cookie fs
, fs_vnode _v
, bool r
)
522 nfs_fs
*nfs
= (nfs_fs
*)fs
;
523 nfs_vnode
*v
= (nfs_vnode
*)_v
;
527 TRACE("nfs_removevnode: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
529 return ERR_UNIMPLEMENTED
;
532 static int nfs_opendir(fs_cookie _fs
, fs_vnode _v
, dir_cookie
*_cookie
)
534 struct nfs_vnode
*v
= (struct nfs_vnode
*)_v
;
535 struct nfs_cookie
*cookie
;
538 TRACE("nfs_opendir: vnode %p\n", v
);
540 if(v
->st
!= STREAM_TYPE_DIR
)
541 return ERR_VFS_NOT_DIR
;
543 cookie
= kmalloc(sizeof(struct nfs_cookie
));
545 return ERR_NO_MEMORY
;
548 cookie
->u
.dir
.nfscookie
= 0;
549 cookie
->u
.dir
.at_end
= false;
556 static int nfs_closedir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
)
558 struct nfs_fs
*fs
= _fs
;
559 struct nfs_vnode
*v
= _v
;
560 struct nfs_cookie
*cookie
= _cookie
;
562 TOUCH(fs
);TOUCH(v
);TOUCH(cookie
);
564 TRACE("nfs_closedir: entry vnode %p, cookie %p\n", v
, cookie
);
566 if(v
->st
!= STREAM_TYPE_DIR
)
567 return ERR_VFS_NOT_DIR
;
575 static int nfs_rewinddir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
)
577 struct nfs_vnode
*v
= _v
;
578 struct nfs_cookie
*cookie
= _cookie
;
583 TRACE("nfs_rewinddir: vnode %p, cookie %p\n", v
, cookie
);
585 if(v
->st
!= STREAM_TYPE_DIR
)
586 return ERR_VFS_NOT_DIR
;
588 mutex_lock(&v
->lock
);
590 cookie
->u
.dir
.nfscookie
= 0;
591 cookie
->u
.dir
.at_end
= false;
593 mutex_unlock(&v
->lock
);
598 #define READDIR_BUF_SIZE (MAXNAMLEN + 64)
600 static ssize_t
_nfs_readdir(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_cookie
*cookie
, void *buf
, ssize_t len
)
602 uint8 resbuf
[READDIR_BUF_SIZE
];
603 nfs_readdirres
*res
= (nfs_readdirres
*)resbuf
;
604 uint8 argbuf
[NFS_READDIRARGS_MAXLEN
];
605 nfs_readdirargs args
;
612 return ERR_VFS_INSUFFICIENT_BUF
; // XXX not quite accurate
614 /* see if we've already hit the end */
615 if(cookie
->u
.dir
.at_end
)
618 /* put together the message */
619 args
.dir
= &v
->nfs_handle
;
620 args
.cookie
= cookie
->u
.dir
.nfscookie
;
621 args
.count
= min(len
, READDIR_BUF_SIZE
);
622 arglen
= nfs_pack_readdirargs(argbuf
, &args
);
624 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_READDIR
, argbuf
, arglen
, resbuf
, sizeof(resbuf
));
629 if(ntohl(res
->status
) != NFS_OK
)
632 /* walk into the buffer, looking for the first entry */
633 if(ntohl(res
->data
[0]) == 0) {
635 cookie
->u
.dir
.at_end
= true;
638 i
= ntohl(res
->data
[0]);
640 /* copy the data out of the first entry */
641 strlcpy(buf
, (char const *)&res
->data
[i
+ 2], ntohl(res
->data
[i
+ 1]) + 1);
643 namelen
= ROUNDUP(ntohl(res
->data
[i
+ 1]), 4);
645 /* update the cookie */
646 cookie
->u
.dir
.nfscookie
= res
->data
[i
+ namelen
/ 4 + 2];
648 return ntohl(res
->data
[i
+ 1]);
651 static int nfs_readdir(fs_cookie _fs
, fs_vnode _v
, dir_cookie _cookie
, void *buf
, size_t len
)
653 struct nfs_fs
*fs
= _fs
;
654 struct nfs_vnode
*v
= _v
;
655 struct nfs_cookie
*cookie
= _cookie
;
660 TRACE("nfs_readdir: vnode %p, cookie %p, len 0x%x\n", v
, cookie
, len
);
662 if(v
->st
!= STREAM_TYPE_DIR
)
663 return ERR_VFS_NOT_DIR
;
665 mutex_lock(&v
->lock
);
667 err
= _nfs_readdir(fs
, v
, cookie
, buf
, len
);
669 mutex_unlock(&v
->lock
);
674 int nfs_open(fs_cookie fs
, fs_vnode _v
, file_cookie
*_cookie
, int oflags
)
676 nfs_fs
*nfs
= (nfs_fs
*)fs
;
677 nfs_vnode
*v
= (nfs_vnode
*)_v
;
683 TRACE("nfs_open: fsid 0x%x, vnid 0x%Lx, oflags 0x%x\n", nfs
->id
, VNODETOVNID(v
), oflags
);
685 if(v
->st
== STREAM_TYPE_DIR
) {
686 err
= ERR_VFS_IS_DIR
;
690 cookie
= kmalloc(sizeof(nfs_cookie
));
697 cookie
->u
.file
.pos
= 0;
698 cookie
->u
.file
.oflags
= oflags
;
700 *_cookie
= (file_cookie
)cookie
;
707 int nfs_close(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
)
709 nfs_fs
*nfs
= (nfs_fs
*)fs
;
710 nfs_vnode
*v
= (nfs_vnode
*)_v
;
714 TRACE("nfs_close: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
716 if(v
->st
== STREAM_TYPE_DIR
)
717 return ERR_VFS_IS_DIR
;
722 int nfs_freecookie(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
)
724 nfs_fs
*nfs
= (nfs_fs
*)fs
;
725 nfs_vnode
*v
= (nfs_vnode
*)_v
;
726 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
730 TRACE("nfs_freecookie: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
732 if(v
->st
== STREAM_TYPE_DIR
)
733 return ERR_VFS_IS_DIR
;
740 int nfs_fsync(fs_cookie fs
, fs_vnode _v
)
742 nfs_fs
*nfs
= (nfs_fs
*)fs
;
743 nfs_vnode
*v
= (nfs_vnode
*)_v
;
747 TRACE("nfs_fsync: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
752 #define READ_BUF_SIZE 1024
754 static ssize_t
nfs_readfile(nfs_fs
*nfs
, nfs_vnode
*v
, nfs_cookie
*cookie
, void *buf
, off_t pos
, ssize_t len
, bool updatecookiepos
)
756 uint8 resbuf
[NFS_READRES_MAXLEN
+ READ_BUF_SIZE
];
759 uint8 argbuf
[NFS_READARGS_MAXLEN
];
763 ssize_t total_read
= 0;
765 TRACE("nfs_readfile: v %p, buf %p, pos %Ld, len %d\n", v
, buf
, pos
, len
);
769 pos
= cookie
->u
.file
.pos
;
770 /* can't do more than 32-bit offsets right now */
773 /* negative or zero length means nothing */
778 ssize_t to_read
= min(len
, READ_BUF_SIZE
);
780 /* put together the message */
781 args
.file
= &v
->nfs_handle
;
783 args
.count
= to_read
;
784 args
.totalcount
= 0; // unused
785 arglen
= nfs_pack_readargs(argbuf
, &args
);
787 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_READ
, argbuf
, arglen
, resbuf
, sizeof(resbuf
));
791 nfs_unpack_readres(resbuf
, &res
);
794 if(res
.status
!= NFS_OK
)
797 /* see how much we read */
798 err
= user_memcpy((uint8
*)buf
+ total_read
, res
.data
, res
.len
);
800 total_read
= err
; // bad user give me bad buffer
806 total_read
+= res
.len
;
808 /* short read, we're done */
809 if((ssize_t
)res
.len
!= to_read
)
814 cookie
->u
.file
.pos
= pos
;
819 ssize_t
nfs_read(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, void *buf
, off_t pos
, ssize_t len
)
821 nfs_fs
*nfs
= (nfs_fs
*)fs
;
822 nfs_vnode
*v
= (nfs_vnode
*)_v
;
823 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
826 TRACE("nfs_read: fsid 0x%x, vnid 0x%Lx, buf %p, pos 0x%Lx, len %ld\n", nfs
->id
, VNODETOVNID(v
), buf
, pos
, len
);
828 if(v
->st
== STREAM_TYPE_DIR
)
829 return ERR_VFS_IS_DIR
;
831 mutex_lock(&v
->lock
);
833 err
= nfs_readfile(nfs
, v
, cookie
, buf
, pos
, len
, true);
835 mutex_unlock(&v
->lock
);
840 #define WRITE_BUF_SIZE 1024
842 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
)
845 uint8 abuf
[sizeof(nfs_writeargs
) + WRITE_BUF_SIZE
];
846 nfs_writeargs
*args
= (nfs_writeargs
*)abuf
;
847 nfs_attrstat
*res
= (nfs_attrstat
*)abuf
;
849 ssize_t total_written
= 0;
853 pos
= cookie
->u
.file
.pos
;
854 /* can't do more than 32-bit offsets right now */
857 /* negative or zero length means nothing */
862 ssize_t to_write
= min(len
, WRITE_BUF_SIZE
);
864 /* put together the message */
865 memcpy(&args
->file
, &v
->nfs_handle
, sizeof(args
->file
));
866 args
->beginoffset
= 0; // unused
867 args
->offset
= htonl(pos
);
868 args
->totalcount
= htonl(to_write
);
869 err
= user_memcpy(args
->data
, (const uint8
*)buf
+ total_written
, to_write
);
875 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_WRITE
, args
, sizeof(*args
) + to_write
, abuf
, sizeof(abuf
));
880 if(ntohl(res
->status
) != NFS_OK
)
885 total_written
+= to_write
;
889 cookie
->u
.file
.pos
= pos
;
891 return total_written
;
893 return ERR_UNIMPLEMENTED
;
896 ssize_t
nfs_write(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, const void *buf
, off_t pos
, ssize_t len
)
898 nfs_fs
*nfs
= (nfs_fs
*)fs
;
899 nfs_vnode
*v
= (nfs_vnode
*)_v
;
900 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
903 TRACE("nfs_write: fsid 0x%x, vnid 0x%Lx, buf %p, pos 0x%Lx, len %ld\n", nfs
->id
, VNODETOVNID(v
), buf
, pos
, len
);
905 mutex_lock(&v
->lock
);
908 case STREAM_TYPE_FILE
:
909 err
= nfs_writefile(nfs
, v
, cookie
, buf
, pos
, len
, true);
911 case STREAM_TYPE_DIR
:
912 err
= ERR_NOT_ALLOWED
;
918 mutex_unlock(&v
->lock
);
923 int nfs_seek(fs_cookie fs
, fs_vnode _v
, file_cookie _cookie
, off_t pos
, seek_type st
)
925 nfs_fs
*nfs
= (nfs_fs
*)fs
;
926 nfs_vnode
*v
= (nfs_vnode
*)_v
;
927 nfs_cookie
*cookie
= (nfs_cookie
*)_cookie
;
929 uint8 attrstatbuf
[NFS_ATTRSTAT_MAXLEN
];
930 nfs_attrstat attrstat
;
933 TRACE("nfs_seek: fsid 0x%x, vnid 0x%Lx, pos 0x%Lx, seek_type %d\n", nfs
->id
, VNODETOVNID(v
), pos
, st
);
935 if(v
->st
== STREAM_TYPE_DIR
)
936 return ERR_VFS_IS_DIR
;
938 mutex_lock(&v
->lock
);
940 err
= nfs_getattr(nfs
, v
, attrstatbuf
, &attrstat
);
944 file_len
= attrstat
.attributes
->size
;
952 cookie
->u
.file
.pos
= pos
;
955 if(pos
+ cookie
->u
.file
.pos
> file_len
)
956 cookie
->u
.file
.pos
= file_len
;
957 else if(pos
+ cookie
->u
.file
.pos
< 0)
958 cookie
->u
.file
.pos
= 0;
960 cookie
->u
.file
.pos
+= pos
;
964 cookie
->u
.file
.pos
= file_len
;
965 else if(pos
+ file_len
< 0)
966 cookie
->u
.file
.pos
= 0;
968 cookie
->u
.file
.pos
= pos
+ file_len
;
971 err
= ERR_INVALID_ARGS
;
975 mutex_unlock(&v
->lock
);
980 int nfs_ioctl(fs_cookie fs
, fs_vnode _v
, file_cookie cookie
, int op
, void *buf
, size_t len
)
982 nfs_fs
*nfs
= (nfs_fs
*)fs
;
983 nfs_vnode
*v
= (nfs_vnode
*)_v
;
987 TRACE("nfs_ioctl: fsid 0x%x, vnid 0x%Lx, op %d, buf %p, len %ld\n", nfs
->id
, VNODETOVNID(v
), op
, buf
, len
);
989 return ERR_UNIMPLEMENTED
;
992 int nfs_canpage(fs_cookie fs
, fs_vnode _v
)
994 nfs_fs
*nfs
= (nfs_fs
*)fs
;
995 nfs_vnode
*v
= (nfs_vnode
*)_v
;
999 TRACE("nfs_canpage: fsid 0x%x, vnid 0x%Lx\n", nfs
->id
, VNODETOVNID(v
));
1001 if(v
->st
== STREAM_TYPE_FILE
)
1007 ssize_t
nfs_readpage(fs_cookie fs
, fs_vnode _v
, iovecs
*vecs
, off_t pos
)
1009 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1010 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1012 ssize_t readfile_return
;
1013 ssize_t total_bytes_read
= 0;
1015 TOUCH(nfs
);TOUCH(v
);
1017 TRACE("nfs_readpage: fsid 0x%x, vnid 0x%Lx, vecs %p, pos 0x%Lx\n", nfs
->id
, VNODETOVNID(v
), vecs
, pos
);
1019 if(v
->st
== STREAM_TYPE_DIR
)
1020 return ERR_VFS_IS_DIR
;
1022 mutex_lock(&v
->lock
);
1024 for (i
=0; i
< vecs
->num
; i
++) {
1025 readfile_return
= nfs_readfile(nfs
, v
, NULL
, vecs
->vec
[i
].start
, pos
, vecs
->vec
[i
].len
, false);
1026 TRACE("nfs_readpage: nfs_readfile returns %d\n", readfile_return
);
1027 if (readfile_return
< 0)
1030 pos
+= readfile_return
;
1031 total_bytes_read
+= readfile_return
;
1033 if ((size_t)readfile_return
< vecs
->vec
[i
].len
) {
1034 /* we have hit the end of file, zero out the rest */
1035 for (; i
< vecs
->num
; i
++) {
1036 memset(vecs
->vec
[i
].start
+ readfile_return
, 0, vecs
->vec
[i
].len
- readfile_return
);
1037 total_bytes_read
+= vecs
->vec
[i
].len
- readfile_return
;
1039 readfile_return
= 0; // after the first pass, wipe out entire pages
1045 mutex_unlock(&v
->lock
);
1047 return total_bytes_read
;
1050 ssize_t
nfs_writepage(fs_cookie fs
, fs_vnode _v
, iovecs
*vecs
, off_t pos
)
1052 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1053 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1055 TOUCH(nfs
);TOUCH(v
);
1057 TRACE("nfs_writepage: fsid 0x%x, vnid 0x%Lx, vecs %p, pos 0x%Lx\n", nfs
->id
, VNODETOVNID(v
), vecs
, pos
);
1059 if(v
->st
== STREAM_TYPE_DIR
)
1060 return ERR_VFS_IS_DIR
;
1062 return ERR_UNIMPLEMENTED
;
1065 static int _nfs_create(nfs_fs
*nfs
, nfs_vnode
*dir
, const char *name
, stream_type type
, vnode_id
*new_vnid
)
1068 uint8 argbuf
[NFS_CREATEARGS_MAXLEN
];
1069 nfs_createargs args
;
1071 uint8 resbuf
[NFS_DIROPRES_MAXLEN
];
1076 /* start building the args */
1077 args
.where
.dir
= &dir
->nfs_handle
;
1078 args
.where
.name
.name
= name
;
1079 args
.attributes
.mode
= 0777;
1080 args
.attributes
.uid
= 0;
1081 args
.attributes
.gid
= 0;
1082 args
.attributes
.size
= 0;
1083 args
.attributes
.atime
.seconds
= 0;
1084 args
.attributes
.atime
.useconds
= 0;
1085 args
.attributes
.mtime
.seconds
= 0;
1086 args
.attributes
.mtime
.useconds
= 0;
1087 arglen
= nfs_pack_createopargs(argbuf
, &args
);
1090 case STREAM_TYPE_FILE
:
1091 proc
= NFSPROC_CREATE
;
1093 case STREAM_TYPE_DIR
:
1094 proc
= NFSPROC_MKDIR
;
1097 panic("_nfs_create asked to make file type it doesn't understand\n");
1100 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, proc
, argbuf
, arglen
, resbuf
, sizeof(resbuf
));
1104 nfs_unpack_diropres(resbuf
, &res
);
1106 if (res
.status
!= NFS_OK
) {
1107 err
= nfs_status_to_error(res
.status
);
1111 /* if new_vnid is null, the layers above us aren't requesting that we bring the vnode into existence */
1112 if (new_vnid
== NULL
) {
1117 /* create a new vnode */
1118 v
= new_vnode_struct(nfs
);
1120 err
= ERR_NO_MEMORY
;
1121 /* weird state here. we've created a file but failed */
1125 /* copy the file handle over */
1126 memcpy(&v
->nfs_handle
, res
.file
, sizeof(v
->nfs_handle
));
1128 /* figure out the stream type from the return value and cache it */
1129 switch (res
.attributes
->ftype
) {
1131 v
->st
= STREAM_TYPE_FILE
;
1134 v
->st
= STREAM_TYPE_DIR
;
1140 /* add it to the handle -> vnode lookup table */
1141 mutex_lock(&nfs
->lock
);
1142 hash_insert(nfs
->handle_hash
, v
);
1143 mutex_unlock(&nfs
->lock
);
1145 /* request that the vfs layer look it up */
1146 err
= vfs_get_vnode(nfs
->id
, VNODETOVNID(v
), (fs_vnode
*)(void *)&v2
);
1148 mutex_lock(&nfs
->lock
);
1149 hash_remove(nfs
->handle_hash
, v
);
1150 mutex_unlock(&nfs
->lock
);
1151 destroy_vnode_struct(v
);
1152 err
= ERR_NOT_FOUND
;
1156 *new_vnid
= VNODETOVNID(v
);
1165 int nfs_create(fs_cookie fs
, fs_vnode _dir
, const char *name
, void *create_args
, vnode_id
*new_vnid
)
1167 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1168 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
1171 TOUCH(nfs
);TOUCH(dir
);
1173 TRACE("nfs_create: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1175 mutex_lock(&dir
->lock
);
1177 err
= _nfs_create(nfs
, dir
, name
, STREAM_TYPE_FILE
, new_vnid
);
1179 mutex_unlock(&dir
->lock
);
1184 static int _nfs_unlink(nfs_fs
*nfs
, nfs_vnode
*dir
, const char *name
, stream_type type
)
1187 uint8 argbuf
[NFS_DIROPARGS_MAXLEN
];
1193 /* start building the args */
1194 args
.dir
= &dir
->nfs_handle
;
1195 args
.name
.name
= name
;
1196 arglen
= nfs_pack_diropargs(argbuf
, &args
);
1199 case STREAM_TYPE_FILE
:
1200 proc
= NFSPROC_REMOVE
;
1202 case STREAM_TYPE_DIR
:
1203 proc
= NFSPROC_RMDIR
;
1206 panic("_nfs_unlink asked to remove file type it doesn't understand\n");
1209 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, proc
, argbuf
, arglen
, &res
, sizeof(res
));
1213 return nfs_status_to_error(ntohl(res
));
1216 int nfs_unlink(fs_cookie fs
, fs_vnode _dir
, const char *name
)
1218 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1219 nfs_vnode
*dir
= (nfs_vnode
*)_dir
;
1222 TOUCH(nfs
);TOUCH(dir
);
1224 TRACE("nfs_unlink: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1226 mutex_lock(&dir
->lock
);
1228 err
= _nfs_unlink(nfs
, dir
, name
, STREAM_TYPE_FILE
);
1230 mutex_unlock(&dir
->lock
);
1235 int nfs_rename(fs_cookie fs
, fs_vnode _olddir
, const char *oldname
, fs_vnode _newdir
, const char *newname
)
1237 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1238 nfs_vnode
*olddir
= (nfs_vnode
*)_olddir
;
1239 nfs_vnode
*newdir
= (nfs_vnode
*)_newdir
;
1241 TOUCH(nfs
);TOUCH(olddir
);TOUCH(newdir
);
1243 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
);
1245 return ERR_UNIMPLEMENTED
;
1248 int nfs_mkdir(fs_cookie _fs
, fs_vnode _base_dir
, const char *name
)
1250 nfs_fs
*nfs
= (nfs_fs
*)_fs
;
1251 nfs_vnode
*dir
= (nfs_vnode
*)_base_dir
;
1254 TOUCH(nfs
);TOUCH(dir
);
1256 TRACE("nfs_mkdir: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1258 mutex_lock(&dir
->lock
);
1260 err
= _nfs_create(nfs
, dir
, name
, STREAM_TYPE_DIR
, NULL
);
1262 mutex_unlock(&dir
->lock
);
1267 int nfs_rmdir(fs_cookie _fs
, fs_vnode _base_dir
, const char *name
)
1269 nfs_fs
*nfs
= (nfs_fs
*)_fs
;
1270 nfs_vnode
*dir
= (nfs_vnode
*)_base_dir
;
1273 TOUCH(nfs
);TOUCH(dir
);
1275 TRACE("nfs_rmdir: fsid 0x%x, vnid 0x%Lx, name '%s'\n", nfs
->id
, VNODETOVNID(dir
), name
);
1277 mutex_lock(&dir
->lock
);
1279 err
= _nfs_unlink(nfs
, dir
, name
, STREAM_TYPE_DIR
);
1281 mutex_unlock(&dir
->lock
);
1286 static int nfs_getattr(nfs_fs
*nfs
, nfs_vnode
*v
, uint8
*buf
, nfs_attrstat
*attrstat
)
1290 err
= rpc_call(&nfs
->rpc
, NFSPROG
, NFSVERS
, NFSPROC_GETATTR
, &v
->nfs_handle
, sizeof(v
->nfs_handle
), buf
, NFS_ATTRSTAT_MAXLEN
);
1294 nfs_unpack_attrstat(buf
, attrstat
);
1296 return nfs_status_to_error(attrstat
->status
);
1299 int nfs_rstat(fs_cookie fs
, fs_vnode _v
, struct file_stat
*stat
)
1301 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1302 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1303 uint8 attrstatbuf
[NFS_ATTRSTAT_MAXLEN
];
1304 nfs_attrstat attrstat
;
1307 TRACE("nfs_rstat: fsid 0x%x, vnid 0x%Lx, stat %p\n", nfs
->id
, VNODETOVNID(v
), stat
);
1309 mutex_lock(&v
->lock
);
1311 err
= nfs_getattr(nfs
, v
, attrstatbuf
, &attrstat
);
1315 if(attrstat
.status
!= NFS_OK
) {
1320 /* copy the stat over from the nfs attrstat */
1321 stat
->vnid
= VNODETOVNID(v
);
1322 stat
->size
= attrstat
.attributes
->size
;
1323 switch(attrstat
.attributes
->ftype
) {
1325 stat
->type
= STREAM_TYPE_FILE
;
1328 stat
->type
= STREAM_TYPE_DIR
;
1331 stat
->type
= STREAM_TYPE_DEVICE
; // XXX should have unknown type
1338 mutex_unlock(&v
->lock
);
1343 int nfs_wstat(fs_cookie fs
, fs_vnode _v
, struct file_stat
*stat
, int stat_mask
)
1345 nfs_fs
*nfs
= (nfs_fs
*)fs
;
1346 nfs_vnode
*v
= (nfs_vnode
*)_v
;
1348 TOUCH(nfs
);TOUCH(v
);
1350 TRACE("nfs_wstat: fsid 0x%x, vnid 0x%Lx, stat %p, stat_mask 0x%x\n", nfs
->id
, VNODETOVNID(v
), stat
, stat_mask
);
1352 return ERR_UNIMPLEMENTED
;
1355 static struct fs_calls nfs_calls
= {
1396 int fs_bootstrap(void);
1397 int fs_bootstrap(void)
1399 dprintf("bootstrap_nfs: entry\n");
1400 return vfs_register_filesystem("nfs", &nfs_calls
);