diff options
Diffstat (limited to 'nfs')
-rw-r--r-- | nfs/ChangeLog | 476 | ||||
-rw-r--r-- | nfs/Makefile | 15 | ||||
-rw-r--r-- | nfs/cache.c | 102 | ||||
-rw-r--r-- | nfs/main.c | 67 | ||||
-rw-r--r-- | nfs/mount.c | 181 | ||||
-rw-r--r-- | nfs/mount.h | 5 | ||||
-rw-r--r-- | nfs/name-cache.c | 305 | ||||
-rw-r--r-- | nfs/nfs-spec.h | 4 | ||||
-rw-r--r-- | nfs/nfs.c | 434 | ||||
-rw-r--r-- | nfs/nfs.h | 50 | ||||
-rw-r--r-- | nfs/ops.c | 822 | ||||
-rw-r--r-- | nfs/pager.c | 448 | ||||
-rw-r--r-- | nfs/rpc.c | 251 | ||||
-rw-r--r-- | nfs/storage-info.c | 104 |
14 files changed, 1625 insertions, 1639 deletions
diff --git a/nfs/ChangeLog b/nfs/ChangeLog deleted file mode 100644 index 57b34160..00000000 --- a/nfs/ChangeLog +++ /dev/null @@ -1,476 +0,0 @@ -Wed May 21 12:07:24 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_create_file): Only attempt chown if the - create succeeded. - -Tue May 20 15:35:39 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs.c (xdr_encode_create_state): New arg OWNER. Set the owner - of the new file to it. All callers changed. - * nfs.h (xdr_encode_create_state): Update prototype. - * ops.c (netfs_attempt_mkdir): If owner didn't get set correctly - (some servers ignore it) then try a chown. - (netfs_attempt_create_file): Likewise. - -Thu Apr 10 13:25:12 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_set_size): Short circuit EACCES to cover - one important case. - -Fri Feb 21 16:47:35 1997 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (netfs_append_args): Present the remote filesystem as a - single argument, in HOST:FS format. - -Wed Feb 12 13:53:42 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_check_open_permissions): If this is a new node, - don't report an error here. (Though, later I/O requests still - might fail.) - -Wed Nov 20 17:13:59 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * Makefile (HURDLIBS): Add iohelp. - -Mon Nov 18 17:01:38 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (guess_mode_use): Delete function. - (netfs_report_access): Use fshelp_access instead of - guess_mode_use. Change return type. - -Sat Nov 16 18:24:55 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * Makefile (SRCS): Remove `cred.c'. - * cred.c: Delete file. - * nfs.h (struct netcred): Delete type. - (cred_has_uid, cred_has_gid): Delete functions. - (nfs_initialize_rpc): netcred arg now iouser. - * ops.c: Change struct netcred to struct iouser throughout. - * pager.c: Likewise. - * cache.c (netfs_node_norefs): Likewise. - * nfs.c (nfs_initialize_rpc): Convert use of netcred to iouser. - -Mon Nov 4 21:23:58 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * rpc.c (rpc_list_lock): Delete variable. Omit all mention of it - throughout this file. Expand the use of outstanding_lock to cover - what rpc_list_lock used to handle. - -Fri Nov 1 18:12:21 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * rpc.c (conduct_rpc): Unlock OUTSTANDING_LOCK if write fails. - -Wed Oct 30 18:25:18 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_statfs): Convert incoming numbers from - network to host byte order. - Don't convert sizes from IOSIZE to BSIZE units. - Return BSIZE in f_bsize field, not IOSIZE. - Fill in f_fsid field. - -Thu Oct 24 23:01:35 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (runtime_argp_children): New variable. - (runtime_argp_parents): Variable removed. - (runtime_argp): Use RUNTIME_ARGP_CHILDREN, not RUNTIME_ARGP_PARENTS. - (main): Rename ARGP_PARENTS to ARGP_CHILDREN, and change the - element type to `struct argp_child'; change the reference in ARGP - accordingly. - -Fri Oct 4 00:00:12 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * mount.c: Add hacks to avoid idiotic sun definitions of TRUE, - FALSE, and malloc in <rpc/types.h>. - * nfs.h (bool_t, enum_t): Typedefs removed. - -Thu Oct 3 12:04:36 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_write): If we get EINTR after having - already written something, return a short count. - - * ops.c (netfs_attempt_create_file): If verify_nonexistent returns - an error, bother to properly unlock NP before returning. - -Mon Sep 30 15:45:31 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (OPT_RSIZE): Changed to 'R'. - (OPT_WSIZE): Changed to 'W'. - (doc): Add general description. - -Thu Sep 26 14:03:07 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs.h (enum_t): New decl. - -Wed Sep 18 13:03:22 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (netfs_append_args): Renamed from netfs_get_options. - Don't initialize ARGZ & ARGZ_LEN anymore. - Add remote filesystem spec to output. - (hold): Variable removed. - (main): Don't use HOLD anymore. - -Thu Sep 12 16:46:47 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * Makefile (HURDLIBS): New variable. - (nfs): Omit special dependency. - -Tue Sep 3 14:00:25 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs-spec.h: Renamed from rpcsvc/nfs_prot.h. - * mount.c: Include "mount.h" instead of <rpcsvc/mount.h>. - * nfs.h: Include "nfs-spec.h" instead of <rpcsvc/nfs_prot.h>. - * rpcsvc/mount.h: Deleted file. - * rpcsvc: Deleted directory. - * mount.h (MOUNTPROG): Renamed from MOUNT_RPC_PROGRAM. - (MOUNTVERS): Renamed from MOUNT_RPC_VERSION. - * Makefile (RPCSVC_FILES): Deleted var. - (lndist, lndist-rpcsvc-files, - $(top_srcdir)/hurd-snap/$(dir)/rpcsvc): Deleted targets. - (LCLHDRS): Added mount.h and nfs-spec.h. - -Thu Aug 29 10:41:27 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * rpcsvc/nfs_prot.h (createmode): Spell EXCLUSIVE correctly. - * nfs.c (hurd_mode_to_nfs_type): New function. - * nfs.h (hurd_mode_to_nfs_type): New decl. - * ops.c (netfs_attempt_rmdir): process_wcc_stat for NP, not DIR. - (netfs_attempt_link): Spell netfs_validate_stat correctly. - (minor, major): New macros. - (netfs_report_access): Don't try and return an error. - - * rpc.c (conduct_rpc): Tolerate and return errors from write. - - * Makefile (RPCSVC_FILES): New variable. - (lndist): Depend on lndist-rpcsvc-files. - (lndist-rpcsvc-files, $(top_srcdir)/hurd-snap/$(dir)/rpcsvc): New - targets. - -Fri Aug 16 11:56:53 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (process_wcc_stat): New function. - (netfs_attempt_chown): Use process_wcc_stat instead of - register_fresh_stat. Pack and unpack v3 SETATTR structure if - appropriate. - (netfs_attempt_chmod): Likewise. - (netfs_attempt_utimes): Likewise. - (netfs_attempt_set_size): Likewise. - (netfs_attempt_lookup): Use process_returned_stat instead of - register_fresh state. Unpack v3 LOOKUP structure if appropriate. - (netfs_attempt_link): Likewise. - (verify_nonexistent): Assert that we are v2. - (netfs_report_access): Use NFS3PROC_ACCESS if we are v3. - (netfs_check_open_permissions): Use netfs_report_access. - (netfs_attempt_readlink): Unpack v3 READLINK structure if - appropriate. - (netfs_attempt_read): Pack and unpack v3 READ structure in - appropriate. Use process_returned_stat instead of - register_fresh_stat. - (netfs_attempt_write): Pack and unpack v3 WRITE structure in - appropriate. Use process_wcc_stat instead of - register_fresh_stat. - (netfs_attempt_create_file): Pack and unpack v3 CREATE structure - if appropriate. Use process_returned_stat instead of - register_fresh_stat. - (netfs_attempt_link) [CHRDEV, BLKDEV, FIFO, SOCK]: If v3, use new - MKNOD call instead of CREATE with overloaded mode. - (netfs_attempt_link) [SYMLINK]: If pack and unpack v3 SYMLINK - structure if appropriate. - (netfs_attempt_unlink): Unpack v3 REMOVE structure if appropriate. - (netfs_attempt_rmdir): Unpack v3 RMDIR structure if appropriate. - (netfs_attempt_rename): Unpack v3 RENAME structure if appropriate. - - * rpcsvc/nfs_prot.h (ACCESS3_READ, ACCESS3_LOOKUP, ACCESS3_MODIFY, - ACCESS3_EXTEND, ACCESS3_DELETE, ACCESS3_EXECUTE): New macros. - - * ops.c (netfs_attempt_chown): Bother to read NFS error/success - value. - -Thu Aug 15 15:24:29 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (verify_nonexistent): Don't need to lock DIR; it's already - locked. - (netfs_attempt_link): Lock DIR *before* calling verify_nonexistent. - - * nfs.c (xdr_encode_fhandle) [protocol_version == 2]: Copy - fhandle->data, not fhandle itself. - -Wed Aug 14 12:33:37 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs.c (xdr_encode_fhandle): Second arg now a `struct fhandle *'. - Encode v3 fhandle if appropriate. - * cache.c: Include <netinet/in.h>. - (hash): New arg `length'. - (lookup_fhandle): Changed to be more like xdr_decode_* functions. - All callers changed. Do the right thing for v3. - (recache_handle): Likewise. - * nfs.h (struct fhandle): New type. - (struct netnode): Member `handle' is now a `struct fhandle'. - (xdr_encode_fhandle): Second arg now a `struct fhandle *'. - (lookup_fhandle, recache_handle): Changed to be more like - xdr_decode_* functions. - - * rpcsvc/nfs_prot.h (enum sattr_time_how): New type. - * nfs.c (xdr_encode_64bit): New function. - (xdr_encode_sattr_mode, xdr_encode_sattr_ids, - xdr_encode_sattr_size, xdr_encode_sattr_times, - xdr_encode_create_state, xdr_encode_sattr_stat): Encode v3 sattr - if appropriate. - (xdr_decode_fattr): Decode v3 fattr if appropriate. - - * rpcsvc/nfs_prot.h (NFS_FHSIZE): Deleted macro. - (NFS2_FHSIZE, NFS3_FHSIZE, NFS3_COOKIEVERFSIZE, NFS3_CREATEVERFSIZE, - NFS3_WRITEVERFSIZE): New macros. - (enum ftype): Deleted NFFIFO. Added NF2FIFO, NF3FIFO, and an - alias NF2BAD for NF3FIFO. - (NFSPROC_NULL, NFSPROC_GETATTR, NFSPROC_SETATTR, - NFSPROC_LOOKUP, NFSPROC_READLINK, NFSPROC_READ, - NFSPROC_WRITE, NFSPROC_CREATE, NFSPROC_REMOVE, - NFSPROC_RENAME, NFSPROC_LINK, NFSPROC_SYMLINK, NFSPROC_MKDIR, - NFSPROC_RMDIR, NFSPROC_READDIR): Replace with new - macros that take a version arg. All users changed to use new - version arg. - (NFS_PROTOCOL_FUNC): New macro. - (NFS2PROC_NULL, NFS2PROC_GETATTR, NFS2PROC_SETATTR, NFS2PROC_ROOT, - NFS2PROC_LOOKUP, NFS2PROC_READLINK, NFS2PROC_READ, - NFS2PROC_WRITECACHE, NFS2PROC_WRIT, NFS2PROC_CREATE, - NFS2PROC_REMOVE, NFS2PROC_RENAME, NFS2PROC_LINK, NFS2PROC_SYMLINK, - NFS2PROC_MKDIR, NFS2PROC_RMDIR, NFS2PROC_READDIR, NFS2PROC_STATFS, - NFS3PROC_NULL, NFS3PROC_GETATTR, NFS3PROC_SETATTR, - NFS3PROC_LOOKUP, NFS3PROC_ACCESS, NFS3PROC_READLINK, - NFS3PROC_READ, NFS3PROC_WRITE, NFS3PROC_CREATE, NFS3PROC_MKDIR, - NFS3PROC_SYMLINK, NFS3PROC_MKNOD, NFS3PROC_REMOVE, NFS3PROC_RMDIR, - NFS3PROC_RENAME, NFS3PROC_LINK, NFS3PROC_READDIR, - NFS3PROC_READDIRPLUS, NFS3PROC_FSSTAT, NFS3PROC_FSINFO, - NFS3PROC_PATHCONF, NFS3PROC_COMMIT): New macros. All callers - appropriately changed. - - * nfs.c (nfs_error_trans): NFS_SERVERFAULT maps to EIO; - NFSERR_BADTYPE maps to EOPNOTSUPP. - - * rpcsvc/nfs_prot.h (nfsstat, ftype, struct nfs_fh, nfs_fh, struct - nfstime, nfstime, struct fattr, fattr, struct sattr, sattr, - filename, nfspath, struct attrstat, attrstat, struct sattrargs, - sattrargs, struct diropargs, diropargs, struct diropokres, - diropokres, struct diropres, diropres, struct readlinkres, - readlinkres, struct readargs, readargs, struct readokres, - readokres, struct readres, readres, struct writeargs, writeargs, - struct createargs, createargs, struct renameargs, renameargs, - struct linkargs, linkargs, struct symlinkargs, symlinkargs, - nfscookie, struct readdirargs, readdirargs, struct entry, entry, - struct dirlist, dirlist, struct readdirres, readdirres, struct - statfsokres, statfsokres, struct statfsres, statfsres): Delete - unused types. - (xdr_nfsstat, xdr_ftype, xdr_nfs_fh, xdr_nfstime, xdr_fattr, - xdr_sattr, xdr_filename, xdr_nfspath, xdr_attrstat, xdr_sattrargs, - xdr_diropargs, xdr_diropokres, xdr_diropres, xdr_readlinkres, - xdr_readargs, xdr_readokres, xdr_readres, xdr_writeargs, - xdr_createargs, xdr_renameargs, xdr_linkargs, xdr_symlinkargs, - xdr_nfscookie, xdr_readdirargs, xdr_entry, xdr_dirlist, - xdr_readdirres, xdr_statfsokres, xdr_statfsres, nfsproc_null_2, - nfsproc_getattr_2, nfsproc_setattr_2, nfsproc_root_2, - nfsproc_lookup_2, nfsproc_readlink_2, rfsproc_read_2, - nfsproc_writecache_2, nfsproc_write_2, nfsproc_create_2, - nfsproc_remove_2, nfsproc_rename_2, nfsproc_link_2, - nfsproc_symlink_2, nfsproc_mkdir_2, nfsproc_rmdir_2, - nfsproc_readdir_2, nfsproc_statfs_2): Delete unused function - declarations. - -Tue Aug 13 14:57:03 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_create_file): Sun's NFS client does not - expect NFSPROC_CREATE to be exclusive. Accordingly, on most - servers (including ours) it isn't exclusive. (Which, of course, - contradicts Sun's own RGC 1094, section 2.2.10.) Which means we - have to insert our own test here to make sure the file doesn't - exist before attempting NFSPROC_CREATE. - (netfs_attempt_link): Likewise. - (verify_nonexistent): New function. - -Mon Aug 12 11:13:58 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs.c (nfs_error_trans): Repair syntax. - -Thu Aug 8 18:48:22 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * nfs.h (protocol_version): New variable. - * mount.c (protocol_version): Define and initialize to `2'. - - * rpcsvc/nfs_prot.h (enum nfsstat): Added new nfsv3 error codes: - NFSERR_XDEV, NFSERR_INVAL, NFSERR_MLINK, NFSERR_REMOTE, - NFSERR_BADHANDLE, NFSERR_NOT_SYNC, NFSERR_BAD_COOKIE, - NFSERR_NOTSUPP, NFSERR_TOOSMALL, NFSERR_SERVERFAULT, - NFSERR_BADTYPE, NFSERR_JUKEBOX. - (NFSERR_TRYLATER): New macro. - * nfs.c (nfs_error_trans): Understand v3 error codes if we are - runnnig v3. - -Wed Jul 31 13:25:00 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_statfs): Use NFSPROC_STATFS, not SETATTR to - do a statfs. - -Tue Jul 23 19:41:07 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * nfs.c (xdr_encode_sattr_times): `struct timespec' now uses a - field prefix of `tv_'. - -Wed Jul 17 13:12:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * main.c (mounted_soft): Initialize to zero. - -Thu Jul 4 17:14:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_link) [case SYMLINK]: Include directory - handle as an RPC arg. - -Wed Jun 26 16:41:00 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (netfs_get_options): New function. - (netfs_parse_runtime_options, netfs_unparse_runtime_options): - Functions removed. - (runtime_argp_parents, runtime_argp, netfs_runtime_argp): New variables. - (main): Use &NETFS_STD_STARTUP_ARGP insteda of NETFS_STARTUP_ARGP. - -Thu Jun 13 09:24:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (SRCS): Remove pager.c. - * nfs.h (struct netnode): Add member `fileinfo'. - * nfs.h (register_fresh_stat): Add decl. - -Wed Jun 12 22:37:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (SRCS): Add pager.c. - -Wed May 22 18:49:16 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (parse_startup_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL. - -Tue May 14 14:00:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_unlink): Add new arg in call to - netfs_attempt_link. - -Sat May 11 01:10:05 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (parse_common_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL. - -Fri May 10 18:15:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_rename, netfs_attempt_link): New parm EXCL, - but don't implement the hard case yet. - -Thu May 9 20:24:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_attempt_statfs): Expect and fill in new statfs - buffer. - -Fri Apr 19 13:50:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * main.c (main): Failure to bind privileged ports is indicated by - EACCES, not EPERM. - -Thu Apr 11 13:51:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (guess_mode_use): New function. - (netfs_check_open_permissions, netfs_report_access): Replace old - clever versions with less obtrusive one. - -Tue Apr 2 09:12:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_report_access): Bother to initialize LEN. - -Fri Mar 29 17:26:14 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * rpc.c: Define malloc to something random around include of rpc/* - header files to avoid bogus definition there. - -Fri Mar 29 17:10:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_report_access): Make sure netfs_attempt_read return - a reasonable LEN. - (netfs_attempt_write): Truncate to THISAMT instead of AMT. - -Tue Mar 19 11:00:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (LCLHDRS): Drop rpc.h. - - * consts.c: Doc fixes. - * cache.c: Likewise. - * cred.c: Likewise. - * main.c: Likewise. - * mount.c: Likewise. - * mount.h: Likewise. - * nfs.c: Likewise. - * ops.c: Likewise. - * rpc.c: Likewise. - - * rpc.c (rpc_receive_thread): Allocate receive buffer big enough - for largest read we expect. - - * cache.c (lookup_fhandle): Correctly install new node in hash - table slot. - - * main.c (parse_startup_opt): Pass STATE, not STATE->argp in call - to argp_error. - - * cache.c (lookup_fhandle): Initialize NN->dead_dir and - NN->dead_name. - - * ops.c: Include <unistd.h>. - (register_fresh_stat): Repair syntax. - -Mon Mar 18 19:49:28 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main, netfs_parse_runtime_options): Pass new arg to - argp_parse. - -Mon Mar 18 11:19:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (register_fresh_stat): Set fs_fsid, st_fstype, st_gen, - st_author, and st_flags here. - * nfs.c (xdr_decode_fattr): Don't set st_fstype, st_gen, - st_author, or st_flags here. - - * ops.c (netfs_attempt_write): Increment OFFSET each time around - the loop. - - * nfs.c (xdr_encode_create_state): Call hurd_mode_to_nfs_mode and - htonl on MODE. - - * nfs.c (xdr_encode_sattr_stat): New function. - -Thu Mar 14 15:11:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * nfs.h (struct netnode): New members `dtrans' and `transarg'. - * cache.c (lookup_fhandle): Initialize NN->dtrans. - (netfs_node_norefs): Free transarg if necessary. - (recache_handle): New function. - * ops.c (netfs_attempt_mkfile): Make dtrans possible if it - isn't already. - (netfs_attempt_unlink): Likewise, when doing the rename hack. - (netfs_attempt_mksymlink): Implement using dtrans and transarg. - (netfs_attempt_mkdev): Likewise. - (register_fresh_stat): If NP->nn->dtrans is set, then mutate the - mode here. - (netfs_attempt_readlink): If NP->nn->dtrans is SYMLINK, then DTRT. - (netfs_attempt_link): Only issue NFSPROC_LINK if dtrans is not - operative. Otherwise, DTRT. - (netfs_attempt_chmod): Implement type-changing using dtrans. - -Tue Mar 12 15:23:32 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ops.c (netfs_set_translator, netfs_attempt_mksymlink, - netfs_attempt_mkdev): New functions. - (netfs_attempt_chmod): Detect attempt to change node type. - (netfs_validate_stat): Clear NP->istranslated. - -Mon Mar 4 16:16:13 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main): Use NETFS_STARTUP_ARGP. - (netfs_parse_runtime_options, netfs_unparse_runtime_options): New funs. - -Wed Feb 28 19:24:23 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (options): New variable. - (main): Parse our arguments. - diff --git a/nfs/Makefile b/nfs/Makefile index f7a7d3bf..10ca2587 100644 --- a/nfs/Makefile +++ b/nfs/Makefile @@ -1,5 +1,7 @@ -# -# Copyright (C) 1995, 1996 Free Software Foundation +# +# Copyright (C) 1995, 1996, 1997, 2000, 2001, 2008, 2011 Free Software +# Foundation, Inc. +# # Written by Michael I. Bushnell. # # This file is part of the GNU Hurd. @@ -23,10 +25,9 @@ makemode := server target = nfs LCLHDRS = nfs.h mount.h nfs-spec.h -SRCS = ops.c rpc.c mount.c nfs.c cache.c consts.c main.c -OBJS = $(subst .c,.o,$(SRCS)) -HURDLIBS=ports netfs fshelp threads iohelp +SRCS = ops.c rpc.c mount.c nfs.c cache.c consts.c main.c name-cache.c \ + storage-info.c +OBJS = $(SRCS:.c=.o) +HURDLIBS = netfs fshelp iohelp threads ports ihash shouldbeinlibc include ../Makeconf - - diff --git a/nfs/cache.c b/nfs/cache.c index e09b7c38..8f87f5d0 100644 --- a/nfs/cache.c +++ b/nfs/cache.c @@ -1,5 +1,5 @@ -/* Node cache management for NFS client implementation - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* cache.c - Node cache management for NFS client implementation. + Copyright (C) 1995, 1996, 1997, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -23,11 +23,15 @@ #include <string.h> #include <netinet/in.h> -/* Hash table containing all the nodes currently active. */ -#define CACHESIZE 512 +/* Hash table containing all the nodes currently active. XXX Was 512, + however, a prime is much nicer for the hash function. 509 is nice + as not only is it prime, it also keeps the array within a page or + two. */ +#define CACHESIZE 509 static struct node *nodehash [CACHESIZE]; -/* Compute and return a hash key for NFS file handle DATA of LEN bytes. */ +/* Compute and return a hash key for NFS file handle DATA of LEN + bytes. */ static inline int hash (int *data, size_t len) { @@ -41,42 +45,40 @@ hash (int *data, size_t len) return h % CACHESIZE; } -/* Lookup the file handle in RPC result at P in the hash table. If it - is not present, initialize a new node structure and insert it into - the hash table. Whichever course, a new reference is generated and - the node is returned in *NPP. Return the address in the RPC result - after the file handle. */ -int * -lookup_fhandle (int *p, struct node **npp) +/* Lookup the file handle P (length LEN) in the hash table. If it is + not present, initialize a new node structure and insert it into the + hash table. Whichever course, a new reference is generated and the + node is returned in *NPP; the lock on the node, (*NPP)->LOCK, is + held. */ +void +lookup_fhandle (void *p, size_t len, struct node **npp) { struct node *np; struct netnode *nn; - size_t len; int h; - if (protocol_version == 2) - len = NFS2_FHSIZE; - else - len = ntohl (*p++); h = hash (p, len); spin_lock (&netfs_node_refcnt_lock); for (np = nodehash[h]; np; np = np->nn->hnext) { if (np->nn->handle.size != len - || bcmp (np->nn->handle.data, p, len) != 0) + || memcmp (np->nn->handle.data, p, len) != 0) continue; np->references++; spin_unlock (&netfs_node_refcnt_lock); mutex_lock (&np->lock); *npp = np; - return p + len / sizeof (int); + return; } + /* Could not find it */ nn = malloc (sizeof (struct netnode)); + assert (nn); + nn->handle.size = len; - bcopy (p, nn->handle.data, len); + memcpy (nn->handle.data, p, len); nn->stat_updated = 0; nn->dtrans = NOT_POSSIBLE; nn->dead_dir = 0; @@ -93,34 +95,57 @@ lookup_fhandle (int *p, struct node **npp) spin_unlock (&netfs_node_refcnt_lock); *npp = np; - return p + len / sizeof (int); } +/* Package holding args to forked_node_delete. */ +struct fnd +{ + struct node *dir; + char *name; +}; + +/* Worker function to delete nodes that don't have any more local + references or links. */ +any_t +forked_node_delete (any_t arg) +{ + struct fnd *args = arg; + + mutex_lock (&args->dir->lock); + netfs_attempt_unlink ((struct iouser *)-1, args->dir, args->name); + netfs_nput (args->dir); + free (args->name); + free (args); + return 0; +}; + /* Called by libnetfs when node NP has no more references. (See - <hurd/libnetfs.h> for details. Just clear local state and remove - from the hash table. */ + <hurd/libnetfs.h> for details. Just clear its local state and + remove it from the hash table. Called and expected to leave with + NETFS_NODE_REFCNT_LOCK held. */ void netfs_node_norefs (struct node *np) { if (np->nn->dead_dir) { - struct node *dir; - char *name; + struct fnd *args; + + args = malloc (sizeof (struct fnd)); + assert (args); np->references++; spin_unlock (&netfs_node_refcnt_lock); - dir = np->nn->dead_dir; - name = np->nn->dead_name; + args->dir = np->nn->dead_dir; + args->name = np->nn->dead_name; np->nn->dead_dir = 0; np->nn->dead_name = 0; netfs_nput (np); - mutex_lock (&dir->lock); - netfs_attempt_unlink ((struct iouser *)-1, dir, name); - - netfs_nput (dir); - free (name); + /* Do this in a separate thread so that we don't wait for it; it + acquires a lock on the dir, which we are not allowed to + do. */ + cthread_detach (cthread_fork (forked_node_delete, (any_t) args)); /* Caller expects us to leave this locked... */ spin_lock (&netfs_node_refcnt_lock); @@ -139,7 +164,7 @@ netfs_node_norefs (struct node *np) /* Change the file handle used for node NP to be the handle at P. Make sure the hash table stays up to date. Return the address - after the hnadle. */ + after the handle. The lock on the node should be held. */ int * recache_handle (int *p, struct node *np) { @@ -149,16 +174,22 @@ recache_handle (int *p, struct node *np) if (protocol_version == 2) len = NFS2_FHSIZE; else - len = ntohl (*p++); + { + len = ntohl (*p); + p++; + } + /* Unlink it */ spin_lock (&netfs_node_refcnt_lock); *np->nn->hprevp = np->nn->hnext; if (np->nn->hnext) np->nn->hnext->nn->hprevp = np->nn->hprevp; + /* Change the name */ np->nn->handle.size = len; - bcopy (p, np->nn->handle.data, len); + memcpy (np->nn->handle.data, p, len); + /* Reinsert it */ h = hash (p, len); np->nn->hnext = nodehash[h]; if (np->nn->hnext) @@ -169,4 +200,3 @@ recache_handle (int *p, struct node *np) return p + len / sizeof (int); } - @@ -1,5 +1,5 @@ /* - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -29,23 +29,34 @@ #include <maptime.h> #include <argp.h> #include <argz.h> +#include <error.h> +#include <version.h> + +char *netfs_server_name = "nfs"; +char *netfs_server_version = HURD_VERSION; extern char *localhost (); /* Default number of times to retry RPCs when mounted soft. */ -#define DEFAULT_SOFT_RETRIES 3 +#define DEFAULT_SOFT_RETRIES 3 /* Default number of seconds to timeout cached stat information. */ #define DEFAULT_STAT_TIMEOUT 3 /* Default number of seconds to timeout cached file contents. */ -#define DEFAULT_CACHE_TIMEOUT 3 +#define DEFAULT_CACHE_TIMEOUT 3 + +/* Default number of seconds to timeout cache positive dir hits. */ +#define DEFAULT_NAME_CACHE_TIMEOUT 3 + +/* Default number of seconds to timeout cache negative dir hits. */ +#define DEFAULT_NAME_CACHE_NEG_TIMEOUT 3 /* Default maximum number of bytes to read at once. */ -#define DEFAULT_READ_SIZE 8192 +#define DEFAULT_READ_SIZE 8192 /* Default maximum number of bytes to write at once. */ -#define DEFAULT_WRITE_SIZE 8192 +#define DEFAULT_WRITE_SIZE 8192 /* Number of seconds to timeout cached stat information. */ @@ -54,6 +65,12 @@ int stat_timeout = DEFAULT_STAT_TIMEOUT; /* Number of seconds to timeout cached file contents. */ int cache_timeout = DEFAULT_CACHE_TIMEOUT; +/* Number of seconds to timeout cached positive dir hits. */ +int name_cache_timeout = DEFAULT_NAME_CACHE_TIMEOUT; + +/* Number of seconds to timeout cached negative dir hits. */ +int name_cache_neg_timeout = DEFAULT_NAME_CACHE_NEG_TIMEOUT; + /* Number of seconds to wait for first retransmission of an RPC. */ int initial_transmit_timeout = 1; @@ -88,19 +105,23 @@ int write_size = DEFAULT_WRITE_SIZE; #define OPT_MNT_PROG -11 #define OPT_NFS_PROG -12 #define OPT_PMAP_PORT -13 +#define OPT_NCACHE_TO -14 +#define OPT_NCACHE_NEG_TO -15 /* Return a string corresponding to the printed rep of DEFAULT_what */ #define ___D(what) #what #define __D(what) ___D(what) #define _D(what) __D(DEFAULT_ ## what) +const char *argp_program_version = STANDARD_HURD_VERSION (nfs); + /* Options usable both at startup and at runtime. */ static const struct argp_option common_options[] = { {0,0,0,0,0,1}, {"soft", OPT_SOFT, "RETRIES", OPTION_ARG_OPTIONAL, - "File system requests will eventually fail, after RETRIES tries if" - " specified, otherwise " _D(SOFT_RETRIES)}, + "File system requests will eventually fail, after RETRIES tries" + " (default " _D(SOFT_RETRIES) ")" }, {"hard", OPT_HARD, 0, 0, "Retry file systems requests until they succeed"}, @@ -117,6 +138,12 @@ static const struct argp_option common_options[] = "Timeout for cached stat information (default " _D(STAT_TIMEOUT) ")"}, {"cache-timeout", OPT_CACHE_TO, "SEC", 0, "Timeout for cached file data (default " _D(CACHE_TIMEOUT) ")"}, + {"name-cache-timeout", OPT_NCACHE_TO, "SEC", 0, + "Timeout for positive directory cache entries (default " + _D(NAME_CACHE_TIMEOUT) ")"}, + {"name-cache-neg-timeout", OPT_NCACHE_NEG_TO, "SEC", 0, + "Timeout for negative directory cache entires (default " + _D(NAME_CACHE_NEG_TIMEOUT) ")"}, {"init-transmit-timeout", OPT_INIT_TR_TO,"SEC", 0}, {"max-transmit-timeout", OPT_MAX_TR_TO, "SEC", 0}, @@ -144,6 +171,8 @@ parse_common_opt (int key, char *arg, struct argp_state *state) case OPT_CACHE_TO: cache_timeout = atoi (arg); break; case OPT_INIT_TR_TO: initial_transmit_timeout = atoi (arg); break; case OPT_MAX_TR_TO: max_transmit_timeout = atoi (arg); break; + case OPT_NCACHE_TO: name_cache_timeout = atoi (arg); break; + case OPT_NCACHE_NEG_TO: name_cache_neg_timeout = atoi (arg); break; default: return ARGP_ERR_UNKNOWN; @@ -174,7 +203,7 @@ static const struct argp_option startup_options[] = { static char *args_doc = "REMOTE_FS [HOST]"; static char *doc = "Hurd nfs translator" "\vIf HOST is not specified, an attempt is made to extract" -" it from REMOTE_FS, using either the `HOST:FS' or `FS@HOST' notations."; +" it from REMOTE_FS using either the `HOST:FS' or `FS@HOST' notations."; static const struct argp_child runtime_argp_children[] = { {&netfs_std_runtime_argp}, {0} }; @@ -182,12 +211,12 @@ static struct argp runtime_argp = { common_options, parse_common_opt, 0, 0, runtime_argp_children }; -/* Use by netfs_set_options to handle runtime option parsing. */ +/* Used by netfs_set_options to handle runtime option parsing. */ struct argp *netfs_runtime_argp = &runtime_argp; /* Where to find the remote filesystem. */ -static char *remote_fs = 0; -static char *host = 0; +static char *remote_fs; /* = 0; */ +static char *host; /* = 0; */ /* Return an argz string describing the current options. Fill *ARGZ with a pointer to newly malloced storage holding the list and *LEN @@ -219,6 +248,8 @@ netfs_append_args (char **argz, size_t *argz_len) FOPT ("--cache-timeout=%d", cache_timeout); FOPT ("--init-transmit-timeout=%d", initial_transmit_timeout); FOPT ("--max-transmit-timeout=%d", max_transmit_timeout); + FOPT ("--name-cache-timeout=%d", name_cache_timeout); + FOPT ("--name-cache-neg-timeout=%d", name_cache_neg_timeout); if (! err) err = netfs_append_std_options (argz, argz_len); @@ -247,6 +278,8 @@ extract_nfs_args (char *spec, char **remote_fs, char **host) char *sep; spec = strdup (spec); /* So we can trash it. */ + if (! spec) + return NULL; sep = index (spec, ':'); if (sep) @@ -318,6 +351,7 @@ parse_startup_opt (int key, char *arg, struct argp_state *state) int main (int argc, char **argv) { + error_t err; struct argp common_argp = { common_options, parse_common_opt }; const struct argp_child argp_children[] = { {&common_argp}, {&netfs_std_startup_argp}, {0} }; @@ -351,14 +385,11 @@ main (int argc, char **argv) } while ((ret == -1) && (errno == EADDRINUSE)); if (ret == -1) - { - perror ("binding main udp socket"); - exit (1); - } + error (1, errno, "binding main udp socket"); - errno = maptime_map (0, 0, &mapped_time); - if (errno) - perror ("mapping time"); + err = maptime_map (0, 0, &mapped_time); + if (err) + error (2, err, "mapping time"); cthread_detach (cthread_fork ((cthread_fn_t) timeout_service_thread, 0)); cthread_detach (cthread_fork ((cthread_fn_t) rpc_receive_thread, 0)); diff --git a/nfs/mount.c b/nfs/mount.c index 965d00a9..6120f87a 100644 --- a/nfs/mount.c +++ b/nfs/mount.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -25,6 +25,7 @@ #undef malloc #include <rpc/pmap_prot.h> #include <errno.h> +#include <error.h> #include <sys/socket.h> #include <netdb.h> #include <string.h> @@ -38,7 +39,7 @@ char *pmap_service_name = "sunrpc"; /* Fallback port number for portmapper */ -short pmap_service_number = PMAPPORT; +short pmap_service_number = PMAPPORT; /* RPC program for mount server. */ int mount_program = MOUNTPROG; @@ -64,13 +65,17 @@ short nfs_port = NFS_PORT; /* True iff NFS_PORT should be used even if portmapper present. */ int nfs_port_override = 0; +/* Host name and port number we actually decided to use. */ +const char *mounted_hostname; +uint16_t mounted_nfs_port; /* host order */ + int protocol_version = 2; /* Set up an RPC for procedure PROCNUM for talking to the portmapper. Allocate storage with malloc and point *BUF at it; caller must free this when done. Return the address where the args for the procedure should be placed. */ -int * +static int * pmap_initialize_rpc (int procnum, void **buf) { return initialize_rpc (PMAPPROG, PMAPVERS, procnum, 0, buf, 0, 0, -1); @@ -80,29 +85,38 @@ pmap_initialize_rpc (int procnum, void **buf) server. Allocate storage with malloc and point *BUF at it; caller must free this when done. Return the address where the args for the procedure should be placed. */ -int * +static int * mount_initialize_rpc (int procnum, void **buf) { return initialize_rpc (MOUNTPROG, MOUNTVERS, procnum, 0, buf, 0, 0, -1); } /* Using the mount protocol, lookup NAME at host HOST. - Return a node for it or null for an error. */ + Return a node for it or null for an error. If an + error occurs, a message is automatically sent to stderr. */ struct node * mount_root (char *name, char *host) { struct sockaddr_in addr; struct hostent *h; - struct servent *s; int *p; void *rpcbuf; int port; + error_t err; struct node *np; short pmapport; /* Lookup the portmapper port number */ if (pmap_service_name) { + struct servent *s; + + /* XXX This will always fail! pmap_service_name will always be "sunrpc" + What should pmap_service_name really be? By definition the second + argument is either "tcp" or "udp" Thus, is this backwards + (as service_name suggests)? If so, should it read: + s = getservbyname (pmap_service_name, "udp"); + or is there something I am missing here? */ s = getservbyname ("sunrpc", pmap_service_name); if (s) pmapport = s->s_port; @@ -119,102 +133,145 @@ mount_root (char *name, char *host) herror (host); return 0; } - + addr.sin_family = h->h_addrtype; - bcopy (h->h_addr_list[0], &addr.sin_addr, h->h_length); + memcpy (&addr.sin_addr, h->h_addr_list[0], h->h_length); addr.sin_port = pmapport; - - connect (main_udp_socket, - (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); - if (!mount_port_override) + if (mount_port_override) + addr.sin_port = htons (mount_port); + else { /* Formulate and send a PMAPPROC_GETPORT request to lookup the mount program on the server. */ + if (connect (main_udp_socket, (struct sockaddr *)&addr, + sizeof (struct sockaddr_in)) == -1) + { + error (0, errno, "server mount program"); + return 0; + } + p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf); - *p++ = htonl (MOUNTPROG); - *p++ = htonl (MOUNTVERS); - *p++ = htonl (IPPROTO_UDP); - *p++ = htonl (0); - errno = conduct_rpc (&rpcbuf, &p); - if (!errno) + if (! p) + { + error (0, errno, "creating rpc packet"); + return 0; + } + + *(p++) = htonl (MOUNTPROG); + *(p++) = htonl (MOUNTVERS); + *(p++) = htonl (IPPROTO_UDP); + *(p++) = htonl (0); + err = conduct_rpc (&rpcbuf, &p); + if (!err) { - port = ntohl (*p++); + port = ntohl (*p); + p++; addr.sin_port = htons (port); } else if (mount_port) addr.sin_port = htons (mount_port); else { - free (rpcbuf); - perror ("portmap of mount"); - return 0; + error (0, err, "portmap of mount"); + goto error_with_rpcbuf; } free (rpcbuf); } - else - addr.sin_port = htons (mount_port); - - /* Now talking to the mount program, fetch the file handle + /* Now, talking to the mount program, fetch a file handle for the root. */ - connect (main_udp_socket, - (struct sockaddr *) &addr, sizeof (struct sockaddr_in)); + if (connect (main_udp_socket, (struct sockaddr *) &addr, + sizeof (struct sockaddr_in)) == -1) + { + error (0, errno, "connect"); + goto error_with_rpcbuf; + } + p = mount_initialize_rpc (MOUNTPROC_MNT, &rpcbuf); + if (! p) + { + error (0, errno, "rpc"); + goto error_with_rpcbuf; + } + p = xdr_encode_string (p, name); - errno = conduct_rpc (&rpcbuf, &p); - if (errno) + err = conduct_rpc (&rpcbuf, &p); + if (err) { - free (rpcbuf); - perror (name); - return 0; + error (0, err, "%s", name); + goto error_with_rpcbuf; } /* XXX Protocol spec says this should be a "unix error code"; we'll - pretend that an NFS error code is what's meant, the numbers match + pretend that an NFS error code is what's meant; the numbers match anyhow. */ - errno = nfs_error_trans (htonl (*p++)); - if (errno) + err = nfs_error_trans (htonl (*p)); + p++; + if (err) { - free (rpcbuf); - perror (name); - return 0; + error (0, err, "%s", name); + goto error_with_rpcbuf; } - + /* Create the node for root */ - lookup_fhandle (p, &np); + xdr_decode_fhandle (p, &np); free (rpcbuf); mutex_unlock (&np->lock); - if (!nfs_port_override) + if (nfs_port_override) + port = nfs_port; + else { - /* Now send another PMAPPROC_GETPORT request to lookup the nfs server. */ + /* Send another PMAPPROC_GETPORT request to lookup the nfs server. */ addr.sin_port = pmapport; - connect (main_udp_socket, - (struct sockaddr *) &addr, sizeof (struct sockaddr_in)); + if (connect (main_udp_socket, (struct sockaddr *) &addr, + sizeof (struct sockaddr_in)) == -1) + { + error (0, errno, "connect"); + return 0; + } + p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf); - *p++ = htonl (NFS_PROGRAM); - *p++ = htonl (NFS_VERSION); - *p++ = htonl (IPPROTO_UDP); - *p++ = htonl (0); - errno = conduct_rpc (&rpcbuf, &p); - if (!errno) - port = ntohl (*p++); + if (! p) + { + error (0, errno, "rpc"); + goto error_with_rpcbuf; + } + *(p++) = htonl (NFS_PROGRAM); + *(p++) = htonl (NFS_VERSION); + *(p++) = htonl (IPPROTO_UDP); + *(p++) = htonl (0); + err = conduct_rpc (&rpcbuf, &p); + if (!err) + { + port = ntohl (*p); + p++; + } else if (nfs_port) port = nfs_port; else { - free (rpcbuf); - perror ("pmap of nfs server"); - return 0; + error (0, err, "portmap of nfs server"); + goto error_with_rpcbuf; } free (rpcbuf); } - else - port = nfs_port; - + addr.sin_port = htons (port); - connect (main_udp_socket, - (struct sockaddr *) &addr, sizeof (struct sockaddr_in)); - + if (connect (main_udp_socket, (struct sockaddr *) &addr, + sizeof (struct sockaddr_in)) == -1) + { + error (0, errno, "connect"); + return 0; + } + + mounted_hostname = host; + mounted_nfs_port = port; + return np; + +error_with_rpcbuf: + free (rpcbuf); + + return 0; } diff --git a/nfs/mount.h b/nfs/mount.h index fce8ee4c..4cb62a83 100644 --- a/nfs/mount.h +++ b/nfs/mount.h @@ -20,6 +20,9 @@ /* These constants define the RPC mount protocol; see RFC 1094. */ +#ifndef NFS_MOUNT_H +#define NFS_MOUNT_H + #define MOUNTPROG 100005 #define MOUNTVERS 1 @@ -33,3 +36,5 @@ #define MOUNTPROC_UMNT 3 #define MOUNTPROC_UMNTALL 4 #define MOUNTPROC_EXPORT 5 + +#endif /* NFS_MOUNT_H */ diff --git a/nfs/name-cache.c b/nfs/name-cache.c new file mode 100644 index 00000000..845cda30 --- /dev/null +++ b/nfs/name-cache.c @@ -0,0 +1,305 @@ +/* Directory name lookup caching + + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Written by Thomas Bushnell, n/BSG, & Miles Bader. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "nfs.h" +#include <string.h> +#include <cacheq.h> + + +/* Maximum number of names to cache at any given time */ +#define MAXCACHE 200 + +/* Maximum length of file name we bother caching */ +#define CACHE_NAME_LEN 100 + +/* Cache entry */ +struct lookup_cache +{ + struct cacheq_hdr hdr; + + /* File handles and lengths for cache entries. 0 for NODE_CACHE_LEN + means a */ + char dir_cache_fh[NFS3_FHSIZE]; + size_t dir_cache_len; + + /* Zero means a `negative' entry -- recording that there's + definitely no node with this name. */ + struct node *np; + + /* Name of the node NODE_CACHE_ID in the directory DIR_CACHE_ID. Entries + with names too long to fit in this buffer aren't cached at all. */ + char name[CACHE_NAME_LEN]; + + /* Strlen of NAME. If this is zero, it's an unused entry. */ + size_t name_len; + + /* Time that this cache entry was created. */ + time_t cache_stamp; + + /* XXX */ + int stati; +}; + +/* The contents of the cache in no particular order */ +static struct cacheq lookup_cache = { sizeof (struct lookup_cache) }; + +static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER; + +/* Buffer to hold statistics */ +static struct stats +{ + long pos_hits; + long neg_hits; + long miss; + long fetch_errors; +} statistics; + +#define PARTIAL_THRESH 100 +#define NPARTIALS (MAXCACHE / PARTIAL_THRESH) +struct stats partial_stats [NPARTIALS]; + + +/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the + cache, return its entry, otherwise 0. CACHE_LOCK must be held. */ +static struct lookup_cache * +find_cache (char *dir, size_t len, const char *name, size_t name_len) +{ + struct lookup_cache *c; + int i; + + /* Search the list. All unused entries are contiguous at the end of the + list, so we can stop searching when we see the first one. */ + for (i = 0, c = lookup_cache.mru; + c && c->name_len; + c = c->hdr.next, i++) + if (c->name_len == name_len + && c->dir_cache_len == len + && c->name[0] == name[0] + && memcmp (c->dir_cache_fh, dir, len) == 0 + && strcmp (c->name, name) == 0) + { + c->stati = i / PARTIAL_THRESH; + return c; + } + + return 0; +} + +/* Node NP has just been found in DIR with NAME. If NP is null, this + name has been confirmed as absent in the directory. DIR is the + fhandle of the directory and LEN is its length. */ +void +enter_lookup_cache (char *dir, size_t len, struct node *np, char *name) +{ + struct lookup_cache *c; + size_t name_len = strlen (name); + + if (name_len > CACHE_NAME_LEN - 1) + return; + + spin_lock (&cache_lock); + + if (lookup_cache.length == 0) + /* There should always be an lru_cache; this being zero means that the + cache hasn't been initialized yet. Do so. */ + cacheq_set_length (&lookup_cache, MAXCACHE); + + /* See if there's an old entry for NAME in DIR. If not, replace the least + recently used entry. */ + c = find_cache (dir, len, name, name_len) ?: lookup_cache.lru; + + /* Fill C with the new entry. */ + memcpy (c->dir_cache_fh, dir, len); + c->dir_cache_len = len; + if (c->np) + netfs_nrele (c->np); + c->np = np; + if (c->np) + netfs_nref (c->np); + strcpy (c->name, name); + c->name_len = name_len; + c->cache_stamp = mapped_time->seconds; + + /* Now C becomes the MRU entry! */ + cacheq_make_mru (&lookup_cache, c); + + spin_unlock (&cache_lock); +} + +/* Purge all references in the cache to NAME within directory DIR. */ +void +purge_lookup_cache (struct node *dp, char *name, size_t namelen) +{ + struct lookup_cache *c, *next; + + spin_lock (&cache_lock); + for (c = lookup_cache.mru; c; c = next) + { + /* Save C->hdr.next, since we may move C from this position. */ + next = c->hdr.next; + + if (c->name_len == namelen + && c->dir_cache_len == dp->nn->handle.size + && memcmp (c->dir_cache_fh, dp->nn->handle.data, + c->dir_cache_len) == 0 + && strcmp (c->name, name) == 0) + { + if (c->np) + netfs_nrele (c->np); + c->name_len = 0; + c->np = 0; + cacheq_make_lru (&lookup_cache, c); /* Use C as the next free + entry. */ + } + } + spin_unlock (&cache_lock); +} + +/* Purge all references in the cache to node NP. */ +void +purge_lookup_cache_node (struct node *np) +{ + struct lookup_cache *c, *next; + + spin_lock (&cache_lock); + for (c = lookup_cache.mru; c; c = next) + { + next = c->hdr.next; + + if (c->np == np) + { + netfs_nrele (c->np); + c->name_len = 0; + c->np = 0; + cacheq_make_lru (&lookup_cache, c); + } + } + spin_unlock (&cache_lock); +} + + + +/* Register a negative hit for an entry in the Nth stat class */ +void +register_neg_hit (int n) +{ + int i; + + statistics.neg_hits++; + + for (i = 0; i < n; i++) + partial_stats[i].miss++; + for (; i < NPARTIALS; i++) + partial_stats[i].neg_hits++; +} + +/* Register a positive hit for an entry in the Nth stat class */ +void +register_pos_hit (int n) +{ + int i; + + statistics.pos_hits++; + + for (i = 0; i < n; i++) + partial_stats[i].miss++; + for (; i < NPARTIALS; i++) + partial_stats[i].pos_hits++; +} + +/* Register a miss */ +void +register_miss () +{ + int i; + + statistics.miss++; + for (i = 0; i < NPARTIALS; i++) + partial_stats[i].miss++; +} + + + +/* Scan the cache looking for NAME inside DIR. If we know nothing + about the entry, then return 0. If the entry is confirmed to not + exist, then return -1. Otherwise, return NP for the entry, with + a newly allocated reference. For all return values other than 0, + unlock DIR->LOCK before returning. For positive hits, lock the + returned node. */ +struct node * +check_lookup_cache (struct node *dir, char *name) +{ + struct lookup_cache *c; + + spin_lock (&cache_lock); + + c = find_cache (dir->nn->handle.data, dir->nn->handle.size, + name, strlen (name)); + if (c) + { + int timeout = c->np + ? name_cache_timeout + : name_cache_neg_timeout; + + /* Make sure the entry is still usable; if not, zap it now. */ + if (mapped_time->seconds - c->cache_stamp >= timeout) + { + register_neg_hit (c->stati); + if (c->np) + netfs_nrele (c->np); + c->name_len = 0; + c->np = 0; + cacheq_make_lru (&lookup_cache, c); + spin_unlock (&cache_lock); + return 0; + } + + cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */ + + if (c->np == 0) + /* A negative cache entry. */ + { + register_neg_hit (c->stati); + spin_unlock (&cache_lock); + mutex_unlock (&dir->lock); + return (struct node *)-1; + } + else + { + struct node *np; + + np = c->np; + netfs_nref (np); + register_pos_hit (c->stati); + spin_unlock (&cache_lock); + + mutex_unlock (&dir->lock); + mutex_lock (&np->lock); + + return np; + } + } + + register_miss (); + spin_unlock (&cache_lock); + + return 0; +} diff --git a/nfs/nfs-spec.h b/nfs/nfs-spec.h index 32f5b09d..bed03874 100644 --- a/nfs/nfs-spec.h +++ b/nfs/nfs-spec.h @@ -1,3 +1,6 @@ +#ifndef NFS_NFS_SPEC_H +#define NFS_NFS_SPEC_H + #define NFS_PORT 2049 #define NFS_MAXDATA 8192 #define NFS_MAXPATHLEN 1024 @@ -162,3 +165,4 @@ enum createmode #define NFS3PROC_PATHCONF 20 #define NFS3PROC_COMMIT 21 +#endif /* NFS_NFS_SPEC_H */ @@ -1,5 +1,8 @@ -/* XDR frobbing and lower level routines for NFS client - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. +/* nfs.c - XDR frobbing and lower level routines for NFS client. + + Copyright (C) 1995, 1996, 1997, 1999, 2002, 2007 + Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -24,12 +27,13 @@ #include <netinet/in.h> #include <stdio.h> -/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return it. */ +/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return + it. */ mode_t nfs_mode_to_hurd_mode (int type, int mode) { int hurdmode; - + switch (type) { case NFDIR: @@ -47,7 +51,7 @@ nfs_mode_to_hurd_mode (int type, int mode) case NFREG: hurdmode = S_IFREG; break; - + case NFLNK: hurdmode = S_IFLNK; break; @@ -65,7 +69,7 @@ nfs_mode_to_hurd_mode (int type, int mode) default: hurdmode = S_IFREG; break; - + case NF2FIFO: hurdmode = S_IFIFO; break; @@ -76,19 +80,19 @@ nfs_mode_to_hurd_mode (int type, int mode) case NF3FIFO: hurdmode = S_IFIFO; break; - + default: hurdmode = S_IFREG; break; } break; } - + hurdmode |= mode & ~NFSMODE_FMT; return hurdmode; } -/* Convert a Hurd mode to an NFS mode */ +/* Convert a Hurd mode to an NFS mode. */ int hurd_mode_to_nfs_mode (mode_t mode) { @@ -97,31 +101,31 @@ hurd_mode_to_nfs_mode (mode_t mode) return mode & 07777; } -/* Convert a Hurd mode to an NFS type */ -int +/* Convert a Hurd mode to an NFS type. */ +int hurd_mode_to_nfs_type (mode_t mode) { switch (mode & S_IFMT) { case S_IFDIR: return NFDIR; - + case S_IFCHR: default: return NFCHR; case S_IFBLK: return NFBLK; - + case S_IFREG: return NFREG; case S_IFLNK: return NFLNK; - + case S_IFSOCK: return NFSOCK; - + case S_IFIFO: return protocol_version == 2 ? NF2FIFO : NF3FIFO; } @@ -131,265 +135,296 @@ hurd_mode_to_nfs_type (mode_t mode) /* Each of the functions on this page copies its second arg to *P, converting it to XDR representation along the way. They then - return the address after the copied value. */ + return the address after the copied value. */ -/* Encode an NFS file handle. */ +/* Encode an NFS file handle. */ int * xdr_encode_fhandle (int *p, struct fhandle *fhandle) { if (protocol_version == 2) { - bcopy (fhandle->data, p, NFS2_FHSIZE); + memcpy (p, fhandle->data, NFS2_FHSIZE); return p + INTSIZE (NFS2_FHSIZE); } else return xdr_encode_data (p, fhandle->data, fhandle->size); } -/* Encode uninterpreted bytes. */ +/* Encode uninterpreted bytes. */ int * xdr_encode_data (int *p, char *data, size_t len) { int nints = INTSIZE (len); - + p[nints] = 0; - *p++ = htonl (len); - bcopy (data, p, len); + *(p++) = htonl (len); + memcpy (p, data, len); return p + nints; } -/* Encode a 64 bit integer */ +/* Encode a 64 bit integer. */ int * xdr_encode_64bit (int *p, long long n) { - *p++ = htonl (n & 0xffffffff00000000LL >> 32); - *p++ = htonl (n & 0xffffffff); + *(p++) = htonl (n & 0xffffffff00000000LL >> 32); + *(p++) = htonl (n & 0xffffffff); return p; } -/* Encode a C string. */ +/* Encode a C string. */ int * xdr_encode_string (int *p, char *string) { return xdr_encode_data (p, string, strlen (string)); } - -/* Encode a MODE into an otherwise empty sattr. */ + +/* Encode a MODE into an otherwise empty sattr. */ int * xdr_encode_sattr_mode (int *p, mode_t mode) { if (protocol_version == 2) { - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = -1; /* size */ - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime usecs */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = -1; /* size */ + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime usecs */ } else { - *p++ = htonl (1); /* set mode */ - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = 0; /* no uid */ - *p++ = 0; /* no gid */ - *p++ = 0; /* no size */ - *p++ = DONT_CHANGE; /* no atime */ - *p++ = DONT_CHANGE; /* no mtime */ + *(p++) = htonl (1); /* set mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = 0; /* no size */ + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ } return p; } -/* Encode UID and GID into an otherwise empty sattr. */ +/* Encode UID and GID into an otherwise empty sattr. */ int * xdr_encode_sattr_ids (int *p, u_int uid, u_int gid) { if (protocol_version == 2) { - *p++ = -1; /* mode */ - *p++ = htonl (uid); - *p++ = htonl (gid); - *p++ = -1; /* size */ - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime usecs */ + *(p++) = -1; /* mode */ + *(p++) = htonl (uid); + *(p++) = htonl (gid); + *(p++) = -1; /* size */ + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime usecs */ } else { - *p++ = 0; /* no mode */ - *p++ = htonl (1); /* set uid */ - *p++ = htonl (uid); - *p++ = htonl (1); /* set gid */ - *p++ = htonl (gid); - *p++ = 0; /* no size */ - *p++ = DONT_CHANGE; /* no atime */ - *p++ = DONT_CHANGE; /* no mtime */ + *(p++) = 0; /* no mode */ + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (uid); + *(p++) = htonl (1); /* set gid */ + *(p++) = htonl (gid); + *(p++) = 0; /* no size */ + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ } return p; } -/* Encode a file size into an otherwise empty sattr. */ +/* Encode a file size into an otherwise empty sattr. */ int * xdr_encode_sattr_size (int *p, off_t size) { if (protocol_version == 2) { - *p++ = -1; /* mode */ - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = htonl (size); - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime secs */ + *(p++) = -1; /* mode */ + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = htonl (size); + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime secs */ } else { - *p++ = 0; /* no mode */ - *p++ = 0; /* no uid */ - *p++ = 0; /* no gid */ - *p++ = htonl (1); /* size */ + *(p++) = 0; /* no mode */ + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = htonl (1); /* size */ p = xdr_encode_64bit (p, size); - *p++ = DONT_CHANGE; /* no atime */ - *p++ = DONT_CHANGE; /* no mtime */ + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ } return p; } -/* Encode ATIME and MTIME into an otherwise empty sattr. */ +/* Encode ATIME and MTIME into an otherwise empty sattr. */ int * xdr_encode_sattr_times (int *p, struct timespec *atime, struct timespec *mtime) { if (protocol_version == 2) { - *p++ = -1; /* mode */ - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = -1; /* size */ - *p++ = htonl (atime->tv_sec); - *p++ = htonl (atime->tv_nsec * 1000); - *p++ = htonl (mtime->tv_sec); - *p++ = htonl (mtime->tv_nsec * 1000); + *(p++) = -1; /* mode */ + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = -1; /* size */ + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec / 1000); + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec / 1000); } else { - *p++ = 0; /* no mode */ - *p++ = 0; /* no uid */ - *p++ = 0; /* no gid */ - *p++ = 0; /* no size */ - *p++ = htonl (SET_TO_CLIENT_TIME); /* atime */ - *p++ = htonl (atime->tv_sec); - *p++ = htonl (atime->tv_nsec); - *p++ = htonl (SET_TO_CLIENT_TIME); /* mtime */ - *p++ = htonl (mtime->tv_sec); - *p++ = htonl (mtime->tv_nsec); + *(p++) = 0; /* no mode */ + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = 0; /* no size */ + *(p++) = htonl (SET_TO_CLIENT_TIME); /* atime */ + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* mtime */ + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec); } return p; } -/* Encode MODE, a size of zero, and the specified owner into an otherwise - empty sattr. */ +/* Encode MODE, a size of zero, and the specified owner into an + otherwise empty sattr. */ int * -xdr_encode_create_state (int *p, +xdr_encode_create_state (int *p, mode_t mode, uid_t owner) { if (protocol_version == 2) { - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = htonl (owner); /* uid */ - *p++ = -1; /* gid */ - *p++ = 0; /* size */ - *p++ = -1; /* atime sec */ - *p++ = -1; /* atime usec */ - *p++ = -1; /* mtime sec */ - *p++ = -1; /* mtime usec */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = htonl (owner); /* uid */ + *(p++) = -1; /* gid */ + *(p++) = 0; /* size */ + *(p++) = -1; /* atime sec */ + *(p++) = -1; /* atime usec */ + *(p++) = -1; /* mtime sec */ + *(p++) = -1; /* mtime usec */ } else { - *p++ = htonl (1); /* mode */ - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = htonl (1); /* set uid */ - *p++ = htonl (owner); - *p++ = 0; /* no gid */ - *p++ = htonl (1); /* set size */ + *(p++) = htonl (1); /* mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (owner); + *(p++) = 0; /* no gid */ + *(p++) = htonl (1); /* set size */ p = xdr_encode_64bit (p, 0); - *p++ = htonl (SET_TO_SERVER_TIME); /* atime */ - *p++ = htonl (SET_TO_SERVER_TIME); /* mtime */ + *(p++) = htonl (SET_TO_SERVER_TIME); /* atime */ + *(p++) = htonl (SET_TO_SERVER_TIME); /* mtime */ } return p; } -/* Encode ST into an sattr. */ +/* Encode ST into an sattr. */ int * xdr_encode_sattr_stat (int *p, struct stat *st) { if (protocol_version == 2) { - *p++ = htonl (hurd_mode_to_nfs_mode (st->st_mode)); - *p++ = htonl (st->st_uid); - *p++ = htonl (st->st_gid); - *p++ = htonl (st->st_size); - *p++ = htonl (st->st_atime); - *p++ = htonl (st->st_atime_usec); - *p++ = htonl (st->st_mtime); - *p++ = htonl (st->st_mtime_usec); + *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode)); + *(p++) = htonl (st->st_uid); + *(p++) = htonl (st->st_gid); + *(p++) = htonl (st->st_size); + *(p++) = htonl (st->st_atim.tv_sec); + *(p++) = htonl (st->st_atim.tv_nsec / 1000); + *(p++) = htonl (st->st_mtim.tv_sec); + *(p++) = htonl (st->st_mtim.tv_nsec / 1000); } else { - *p++ = htonl (1); /* set mode */ - *p++ = htonl (hurd_mode_to_nfs_mode (st->st_mode)); - *p++ = htonl (1); /* set uid */ - *p++ = htonl (st->st_uid); - *p++ = htonl (1); /* set gid */ - *p++ = htonl (st->st_gid); - *p++ = htonl (1); /* set size */ + *(p++) = htonl (1); /* set mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode)); + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (st->st_uid); + *(p++) = htonl (1); /* set gid */ + *(p++) = htonl (st->st_gid); + *(p++) = htonl (1); /* set size */ p = xdr_encode_64bit (p, st->st_size); - *p++ = htonl (SET_TO_CLIENT_TIME); /* set atime */ - *p++ = htonl (st->st_atime); - *p++ = htonl (st->st_atime_usec * 1000); - *p++ = htonl (SET_TO_CLIENT_TIME); /* set mtime */ - *p++ = htonl (st->st_mtime); - *p++ = htonl (st->st_mtime_usec * 1000); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* set atime */ + *(p++) = htonl (st->st_atim.tv_sec); + *(p++) = htonl (st->st_atim.tv_nsec); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* set mtime */ + *(p++) = htonl (st->st_mtim.tv_sec); + *(p++) = htonl (st->st_mtim.tv_nsec); } return p; } -/* Decode *P into a long long; return the address of the following data. */ +/* Decode *P into a long long; return the address of the following + data. */ int * xdr_decode_64bit (int *p, long long *n) { long long high, low; - high = ntohl (*p++); - low = ntohl (*p++); + high = ntohl (*p); + p++; + low = ntohl (*p); + p++; *n = ((high & 0xffffffff) << 32) | (low & 0xffffffff); return p; } +/* Decode *P into an fhandle and look up the associated node. Return + the address of the following data. */ +int * +xdr_decode_fhandle (int *p, struct node **npp) +{ + size_t len; + + if (protocol_version == 2) + len = NFS2_FHSIZE; + else + { + len = ntohl (*p); + p++; + } + /* Enter into cache. */ + lookup_fhandle (p, len, npp); + return p + len / sizeof (int); +} + /* Decode *P into a stat structure; return the address of the - following data. */ + following data. */ int * xdr_decode_fattr (int *p, struct stat *st) { int type, mode; - - type = ntohl (*p++); - mode = ntohl (*p++); + + type = ntohl (*p); + p++; + mode = ntohl (*p); + p++; st->st_mode = nfs_mode_to_hurd_mode (type, mode); - st->st_nlink = ntohl (*p++); - st->st_uid = ntohl (*p++); - st->st_gid = ntohl (*p++); + st->st_nlink = ntohl (*p); + p++; + st->st_uid = ntohl (*p); + p++; + st->st_gid = ntohl (*p); + p++; if (protocol_version == 2) { - st->st_size = ntohl (*p++); - st->st_blksize = ntohl (*p++); - st->st_rdev = ntohl (*p++); - st->st_blocks = ntohl (*p++); + st->st_size = ntohl (*p); + p++; + st->st_blksize = ntohl (*p); + p++; + st->st_rdev = ntohl (*p); + p++; + st->st_blocks = ntohl (*p); + p++; } else { @@ -400,26 +435,34 @@ xdr_decode_fattr (int *p, struct stat *st) p = xdr_decode_64bit (p, &size); st->st_blocks = size / 512; st->st_blksize = read_size < write_size ? read_size : write_size; - major = ntohl (*p++); - minor = ntohl (*p++); -/* XXX - Temporary */ -#define makedev(maj,min) ((((maj)&0xFF)<<8)+((min)&0xFF)) + major = ntohl (*p); + p++; + minor = ntohl (*p); + p++; st->st_rdev = makedev (major, minor); } - st->st_fsid = ntohl (*p++); - st->st_ino = ntohl (*p++); - st->st_atime = ntohl (*p++); - st->st_atime_usec = ntohl (*p++); - st->st_mtime = ntohl (*p++); - st->st_mtime_usec = ntohl (*p++); - st->st_ctime = ntohl (*p++); - st->st_ctime_usec = ntohl (*p++); - - if (protocol_version == 3) + st->st_fsid = ntohl (*p); + p++; + st->st_ino = ntohl (*p); + p++; + st->st_atim.tv_sec = ntohl (*p); + p++; + st->st_atim.tv_nsec = ntohl (*p); + p++; + st->st_mtim.tv_sec = ntohl (*p); + p++; + st->st_mtim.tv_nsec = ntohl (*p); + p++; + st->st_ctim.tv_sec = ntohl (*p); + p++; + st->st_ctim.tv_nsec = ntohl (*p); + p++; + + if (protocol_version < 3) { - st->st_atime_usec /= 1000; - st->st_mtime_usec /= 1000; - st->st_ctime_usec /= 1000; + st->st_atim.tv_nsec *= 1000; + st->st_mtim.tv_nsec *= 1000; + st->st_ctim.tv_nsec *= 1000; } return p; @@ -427,14 +470,15 @@ xdr_decode_fattr (int *p, struct stat *st) } /* Decode *P into a string, stored at BUF; return the address - of the following data. */ + of the following data. */ int * xdr_decode_string (int *p, char *buf) { int len; - - len = ntohl (*p++); - bcopy (p, buf, len); + + len = ntohl (*p); + p++; + memcpy (buf, p, len); buf[len] = '\0'; return p + INTSIZE (len); } @@ -447,7 +491,7 @@ xdr_decode_string (int *p, char *buf) means superuser), NP (identifying the node we are operating on), and SECOND_GID (specifying another GID the server might be interested in). Allocate at least LEN bytes of space for bulk data in - addition to the normal amount for an RPC. */ + addition to the normal amount for an RPC. */ int * nfs_initialize_rpc (int rpc_proc, struct iouser *cred, size_t len, void **bufp, struct node *np, @@ -456,9 +500,10 @@ nfs_initialize_rpc (int rpc_proc, struct iouser *cred, uid_t uid; uid_t gid; error_t err; - + /* Use heuristics to figure out what ids to present to the server. - Don't lie, but adjust ids as necessary to secure the desired result. */ + Don't lie, but adjust ids as necessary to secure the desired + result. */ if (cred == (struct iouser *) -1) { @@ -523,7 +568,7 @@ nfs_initialize_rpc (int rpc_proc, struct iouser *cred, gid = np->nn_stat.st_gid; else gid = cred->gids->ids[0]; - } + } if (second_gid != -1 && !idvec_contains (cred->gids, second_gid)) second_gid = -1; @@ -537,7 +582,8 @@ nfs_initialize_rpc (int rpc_proc, struct iouser *cred, uid, gid, second_gid); } -/* ERROR is an NFS error code; return the correspending Hurd error. */ +/* ERROR is an NFS error code; return the correspending Hurd + error. */ error_t nfs_error_trans (int error) { @@ -545,55 +591,55 @@ nfs_error_trans (int error) { case NFS_OK: return 0; - + case NFSERR_PERM: return EPERM; case NFSERR_NOENT: return ENOENT; - + case NFSERR_IO: return EIO; - + case NFSERR_NXIO: return ENXIO; - + case NFSERR_ACCES: return EACCES; - + case NFSERR_EXIST: return EEXIST; - + case NFSERR_NODEV: return ENODEV; - + case NFSERR_NOTDIR: return ENOTDIR; - + case NFSERR_ISDIR: return EISDIR; - + case NFSERR_FBIG: return E2BIG; - + case NFSERR_NOSPC: return ENOSPC; case NFSERR_ROFS: return EROFS; - + case NFSERR_NAMETOOLONG: return ENAMETOOLONG; - + case NFSERR_NOTEMPTY: return ENOTEMPTY; - + case NFSERR_DQUOT: return EDQUOT; - + case NFSERR_STALE: return ESTALE; - + case NFSERR_WFLUSH: /* Not known in v3, but we just give EINVAL for unknown errors so it's the same. */ @@ -607,15 +653,15 @@ nfs_error_trans (int error) { case NFSERR_XDEV: return EXDEV; - + case NFSERR_INVAL: case NFSERR_REMOTE: /* not sure about this one */ default: return EINVAL; - + case NFSERR_MLINK: return EMLINK; - + case NFSERR_NOTSUPP: case NFSERR_BADTYPE: return EOPNOTSUPP; @@ -628,7 +674,7 @@ nfs_error_trans (int error) case NFSERR_BAD_COOKIE: case NFSERR_TOOSMALL: case NFSERR_JUKEBOX: /* ??? */ - /* These indicate bugs in the client, so EGRATUITOUS is right. */ + /* These indicate bugs in the client, so EGRATUITOUS is right. */ return EGRATUITOUS; } } @@ -1,5 +1,5 @@ /* Data structures and global variables for NFS client - Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation + Copyright (C) 1994,95,96,97,99,2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -15,8 +15,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef NFS_NFS_H +#define NFS_NFS_H + #include <sys/stat.h> #include <sys/types.h> +#include <stdint.h> +#include <sys/mman.h> #include "nfs-spec.h" #include <hurd/netfs.h> @@ -25,13 +30,13 @@ struct fhandle { size_t size; - /* Leave enough room for the biggest possible fhandle. */ + /* Leave enough room for the largest possible fhandle. */ char data[NFS3_FHSIZE]; }; -/* One of these exists for private data needed by the client for each +/* There exists one of there for the private data needed by each client node. */ -struct netnode +struct netnode { struct fhandle handle; time_t stat_updated; @@ -54,9 +59,9 @@ struct netnode char *name; dev_t indexes; } transarg; - + #ifdef notyet - /* This indicates that the length of the file must be at + /* This indicates that the length of the file must be at least this big because we've written this much locally, even if the server thinks we haven't gone this far. */ off_t extend_len; @@ -65,8 +70,8 @@ struct netnode struct user_pager_info *fileinfo; /* If this node has been renamed by "deletion" then - this is the directory and name in that directory which - is holding the node */ + this is the directory and the name in that directory + which is holding the node */ struct node *dead_dir; char *dead_name; }; @@ -77,7 +82,7 @@ int main_udp_socket; /* Our hostname */ char *hostname; -/* The current time */ +/* The current time */ volatile struct mapped_time_value *mapped_time; /* Some tunable parameters */ @@ -88,6 +93,12 @@ extern int stat_timeout; /* How long to keep around file contents caches */ extern int cache_timeout; +/* How long to keep around positive dir cache entries */ +extern int name_cache_timeout; + +/* How long to keep around negative dir cache entries */ +extern int name_cache_neg_timeout; + /* How long to wait for replies before re-sending RPC's. */ extern int initial_transmit_timeout; extern int max_transmit_timeout; @@ -117,7 +128,7 @@ extern int mount_program; /* RPC program version for the mount agent */ extern int mount_version; -/* If this is nonzero, it's the port to use for the mount agent if +/* If this is nonzero, it's the port to use for the mount agent if the portmapper fails or can't be found. */ extern short mount_port; @@ -131,7 +142,7 @@ extern int nfs_program; /* RPC program version for the NFS server */ extern int nfs_version; -/* If this is nonzero, it's the port to be used to find the nfs agent +/* If this is nonzero, it's the port to be used to find the nfs agent if the portmapper fails or can't be found */ extern short nfs_port; @@ -143,7 +154,7 @@ extern int nfs_port_override; extern int protocol_version; -/* Count how many four-byte chunks it takss to hold LEN bytes. */ +/* Count how many four-byte chunks it takes to hold LEN bytes. */ #define INTSIZE(len) (((len)+3)>>2) @@ -160,12 +171,15 @@ int *xdr_encode_sattr_stat (int *, struct stat *); int *xdr_encode_create_state (int *, mode_t, uid_t); int *xdr_decode_fattr (int *, struct stat *); int *xdr_decode_string (int *, char *); -int *nfs_initialize_rpc (int, struct iouser *, size_t, void **, +int *xdr_decode_fhandle (int *, struct node **); +int *nfs_initialize_rpc (int, struct iouser *, size_t, void **, struct node *, uid_t); error_t nfs_error_trans (int); /* mount.c */ struct node *mount_root (char *, char *); +extern const char *mounted_hostname; +extern uint16_t mounted_nfs_port; /* host order */ /* ops.c */ int *register_fresh_stat (struct node *, int *); @@ -177,5 +191,13 @@ void timeout_service_thread (void); void rpc_receive_thread (void); /* cache.c */ -int *lookup_fhandle (int *, struct node **); +void lookup_fhandle (void *, size_t, struct node **); int *recache_handle (int *, struct node *); + +/* name-cache.c */ +void enter_lookup_cache (char *, size_t, struct node *, char *); +void purge_lookup_cache (struct node *, char *, size_t); +struct node *check_lookup_cache (struct node *, char *); +void purge_lookup_cache_node (struct node *); + +#endif /* NFS_NFS_H */ @@ -1,5 +1,5 @@ -/* Libnetfs callbacks for node operations in NFS client - Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation +/* ops.c - Libnetfs callbacks for node operations in NFS client. + Copyright (C) 1994,95,96,97,99,2002,2011 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,17 +21,19 @@ #include <string.h> #include <fcntl.h> #include <stdio.h> +#include <stddef.h> #include <dirent.h> #include <unistd.h> +#include <maptime.h> -/* We have fresh stat information for NP; the fattr structure is at - P. Update our entry. Return the address of the next int after - the fattr structure. */ +/* We have fresh stat information for NP; the file attribute (fattr) + structure is at P. Update our entry. Return the address of the next + int after the fattr structure. */ int * register_fresh_stat (struct node *np, int *p) { int *ret; - + ret = xdr_decode_fattr (p, &np->nn_stat); np->nn->stat_updated = mapped_time->seconds; @@ -40,12 +42,12 @@ register_fresh_stat (struct node *np, int *p) case NOT_POSSIBLE: case POSSIBLE: break; - + case SYMLINK: np->nn_stat.st_size = strlen (np->nn->transarg.name); np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT) | S_IFLNK); break; - + case CHRDEV: np->nn_stat.st_rdev = np->nn->transarg.indexes; np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT) | S_IFCHR); @@ -70,7 +72,8 @@ register_fresh_stat (struct node *np, int *p) np->nn_stat.st_gen = 0; np->nn_stat.st_author = np->nn_stat.st_uid; np->nn_stat.st_flags = 0; - + np->nn_translated = np->nn_stat.st_mode & S_IFMT; + return ret; } @@ -82,13 +85,14 @@ register_fresh_stat (struct node *np, int *p) int * process_returned_stat (struct node *np, int *p, int mod) { - int attrs_exist; - if (protocol_version == 2) return register_fresh_stat (np, p); else { - attrs_exist = ntohl (*p++); + int attrs_exist; + + attrs_exist = ntohl (*p); + p++; if (attrs_exist) p = register_fresh_stat (np, p); else if (mod) @@ -102,8 +106,8 @@ process_returned_stat (struct node *np, int *p, int mod) /* Handle returned wcc information for various calls. In protocol version 2, this is just register_fresh_stat. In version 3, it does the wcc_data interpretation too. If this follows an operation that - we expect has modified the attributes, MOD should be set. - (This unpacks the wcc_data XDR type.) */ + we expect has modified the attributes, MOD should be set. + (This unpacks the wcc_data XDR type.) */ int * process_wcc_stat (struct node *np, int *p, int mod) { @@ -114,7 +118,8 @@ process_wcc_stat (struct node *np, int *p, int mod) int attrs_exist; /* First the pre_op_attr */ - attrs_exist = ntohl (*p++); + attrs_exist = ntohl (*p); + p++; if (attrs_exist) { /* Just skip them for now */ @@ -122,7 +127,7 @@ process_wcc_stat (struct node *np, int *p, int mod) p += 2 * sizeof (int); /* mtime */ p += 2 * sizeof (int); /* atime */ } - + /* Now the post_op_attr */ return process_returned_stat (np, p, mod); } @@ -130,35 +135,39 @@ process_wcc_stat (struct node *np, int *p, int mod) /* Implement the netfs_validate_stat callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_validate_stat (struct node *np, struct iouser *cred) { int *p; void *rpcbuf; error_t err; - + if (mapped_time->seconds - np->nn->stat_updated < stat_timeout) return 0; p = nfs_initialize_rpc (NFSPROC_GETATTR (protocol_version), (struct iouser *) -1, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - + err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } if (!err) register_fresh_stat (np, p); - np->istranslated = 0; - free (rpcbuf); return err; } /* Implement the netfs_attempt_chown callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_chown (struct iouser *cred, struct node *np, uid_t uid, gid_t gid) @@ -166,24 +175,28 @@ netfs_attempt_chown (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version), cred, 0, &rpcbuf, np, gid); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_sattr_ids (p, uid, gid); if (protocol_version == 3) - *p++ = 0; /* guard_check == 0 */ - + *(p++) = 0; /* guard_check == 0 */ + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_wcc_stat (np, p, !err); } free (rpcbuf); - + return err; } @@ -197,7 +210,7 @@ netfs_attempt_chauthor (struct iouser *cred, struct node *rp, } /* Implement the netfs_attempt_chmod callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode) @@ -211,26 +224,29 @@ netfs_attempt_chmod (struct iouser *cred, struct node *np, err = netfs_validate_stat (np, cred); if (err) return err; + + /* Has the file type changed? (e.g. from symlink to + directory). */ if ((mode & S_IFMT) != (np->nn_stat.st_mode & S_IFMT)) { char *f = 0; - + if (np->nn->dtrans == NOT_POSSIBLE) return EOPNOTSUPP; - + if (np->nn->dtrans == SYMLINK) f = np->nn->transarg.name; - + switch (mode & S_IFMT) { default: return EOPNOTSUPP; - + case S_IFIFO: np->nn->dtrans = FIFO; np->nn->stat_updated = 0; break; - + case S_IFSOCK: np->nn->dtrans = SOCK; np->nn->stat_updated = 0; @@ -243,26 +259,30 @@ netfs_attempt_chmod (struct iouser *cred, struct node *np, p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_sattr_mode (p, mode); if (protocol_version == 3) - *p++ = 0; /* guard check == 0 */ - + *(p++) = 0; /* guard check == 0 */ + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_wcc_stat (np, p, !err); } - + free (rpcbuf); return err; } /* Implement the netfs_attempt_chflags callback as described in - <hurd/netfs.h>. */ -error_t + <hurd/netfs.h>. */ +error_t netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags) { @@ -278,18 +298,35 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + struct timeval tv; + struct timespec current; + + /* XXX For version 3 we can actually do this right, but we don't + just yet. */ + if (!atime || !mtime) + { + maptime_read (mapped_time, &tv); + current.tv_sec = tv.tv_sec; + current.tv_nsec = tv.tv_usec * 1000; + } + p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - p = xdr_encode_sattr_times (p, atime, mtime); + p = xdr_encode_sattr_times (p, + atime ?: ¤t, + mtime ?: ¤t); if (protocol_version == 3) - *p++ = 0; /* guard check == 0 */ - + *(p++) = 0; /* guard check == 0 */ + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_wcc_stat (np, p, !err); } @@ -299,7 +336,7 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np, } /* Implement the netfs_attempt_set_size callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size) @@ -307,22 +344,26 @@ netfs_attempt_set_size (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_sattr_size (p, size); if (protocol_version == 3) - *p++ = 0; /* guard_check == 0 */ - + *(p++) = 0; /* guard_check == 0 */ + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_wcc_stat (np, p, !err); } - + /* If we got EACCES, but the user has the file open for writing, then the NFS protocol has screwed us. There's nothing we can do, except in the important case of opens with @@ -332,12 +373,9 @@ netfs_attempt_set_size (struct iouser *cred, struct node *np, does have the file open for writing. */ if (err == EACCES) { - err = netfs_validate_stat (np, cred); - if (!err && np->nn_stat.st_size == size) + int error = netfs_validate_stat (np, cred); + if (!error && np->nn_stat.st_size == size) err = 0; - else - /* Never mind, put the old error back */ - err = EACCES; } free (rpcbuf); @@ -353,34 +391,44 @@ netfs_attempt_statfs (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + p = nfs_initialize_rpc (NFS2PROC_STATFS, cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - + err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); - + { + err = nfs_error_trans (ntohl (*p)); + p++; + } + if (!err) { p++; /* skip IOSIZE field */ - st->f_bsize = ntohl (*p++); - st->f_blocks = ntohl (*p++); - st->f_bfree = ntohl (*p++); - st->f_bavail = ntohl (*p++); + st->f_bsize = ntohl (*p); + p++; + st->f_blocks = ntohl (*p); + p++; + st->f_bfree = ntohl (*p); + p++; + st->f_bavail = ntohl (*p); + p++; st->f_type = FSTYPE_NFS; st->f_files = 0; st->f_ffree = 0; st->f_fsid = getpid (); st->f_namelen = 0; } - + free (rpcbuf); return err; } /* Implement the netfs_attempt_sync callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_sync (struct iouser *cred, struct node *np, int wait) { @@ -397,7 +445,7 @@ netfs_attempt_syncfs (struct iouser *cred, int wait) } /* Implement the netfs_attempt_read callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_read (struct iouser *cred, struct node *np, off_t offset, size_t *len, void *data) @@ -408,7 +456,7 @@ netfs_attempt_read (struct iouser *cred, struct node *np, error_t err; size_t amt, thisamt; int eof; - + for (amt = *len; amt;) { thisamt = amt; @@ -417,16 +465,20 @@ netfs_attempt_read (struct iouser *cred, struct node *np, p = nfs_initialize_rpc (NFSPROC_READ (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - *p++ = htonl (offset); - *p++ = htonl (thisamt); + *(p++) = htonl (offset); + *(p++) = htonl (thisamt); if (protocol_version == 2) - *p++ = 0; - + *(p++) = 0; + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_returned_stat (np, p, !err); @@ -436,23 +488,27 @@ netfs_attempt_read (struct iouser *cred, struct node *np, free (rpcbuf); return err; } - - trans_len = ntohl (*p++); + + trans_len = ntohl (*p); + p++; if (trans_len > thisamt) trans_len = thisamt; /* ??? */ if (protocol_version == 3) - eof = ntohl (*p++); + { + eof = ntohl (*p); + p++; + } else eof = (trans_len < thisamt); - - bcopy (p, data, trans_len); + + memcpy (data, p, trans_len); free (rpcbuf); data += trans_len; offset += trans_len; amt -= trans_len; - + if (eof) { *len -= amt; @@ -462,9 +518,9 @@ netfs_attempt_read (struct iouser *cred, struct node *np, } return 0; } - + /* Implement the netfs_attempt_write callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_write (struct iouser *cred, struct node *np, off_t offset, size_t *len, void *data) @@ -474,62 +530,66 @@ netfs_attempt_write (struct iouser *cred, struct node *np, error_t err; size_t amt, thisamt; size_t count; - + for (amt = *len; amt;) { thisamt = amt; if (thisamt > write_size) thisamt = write_size; - + p = nfs_initialize_rpc (NFSPROC_WRITE (protocol_version), cred, thisamt, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); if (protocol_version == 2) - *p++ = 0; - *p++ = htonl (offset); + *(p++) = 0; + *(p++) = htonl (offset); if (protocol_version == 2) - *p++ = 0; + *(p++) = 0; if (protocol_version == 3) - *p++ = htonl (FILE_SYNC); + *(p++) = htonl (FILE_SYNC); p = xdr_encode_data (p, data, thisamt); - + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err || protocol_version == 3) p = process_wcc_stat (np, p, !err); if (!err) { if (protocol_version == 3) { - count = ntohl (*p++); + count = ntohl (*p); + p++; p++; /* ignore COMMITTED */ /* ignore verf for now */ - p += NFS3_WRITEVERFSIZE / sizeof (int); + p += NFS3_WRITEVERFSIZE / sizeof (int); } else /* assume it wrote the whole thing */ count = thisamt; - - free (rpcbuf); + amt -= count; data += count; offset += count; } } - + + free (rpcbuf); + if (err == EINTR && amt != *len) { *len -= amt; - free (rpcbuf); return 0; } - + if (err) { *len = 0; - free (rpcbuf); return err; } } @@ -544,18 +604,29 @@ verify_nonexistent (struct iouser *cred, struct node *dir, int *p; void *rpcbuf; error_t err; - + + /* Don't use the lookup cache for this; we want a full sync to + get as close to real exclusive create behavior as possible. */ + assert (protocol_version == 2); p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); - + { + err = nfs_error_trans (ntohl (*p)); + p++; + } + + free (rpcbuf); + if (!err) return EEXIST; else @@ -563,7 +634,7 @@ verify_nonexistent (struct iouser *cred, struct node *dir, } /* Implement the netfs_attempt_lookup callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_lookup (struct iouser *cred, struct node *np, char *name, struct node **newnp) @@ -571,21 +642,45 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + char dirhandle[NFS3_FHSIZE]; + size_t dirlen; + + /* Check the cache first. */ + *newnp = check_lookup_cache (np, name); + if (*newnp) + { + if (*newnp == (struct node *) -1) + { + *newnp = 0; + return ENOENT; + } + else + return 0; + } + p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_string (p, name); - + + /* Remember the directory handle for later cache use. */ + + dirlen = np->nn->handle.size; + memcpy (dirhandle, np->nn->handle.data, dirlen); + mutex_unlock (&np->lock); err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err) { - p = lookup_fhandle (p, newnp); + p = xdr_decode_fhandle (p, newnp); p = process_returned_stat (*newnp, p, 1); } if (err) @@ -595,7 +690,7 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np, if (*newnp) mutex_unlock (&(*newnp)->lock); mutex_lock (&np->lock); - p = process_returned_stat (np, p, 0); + p = process_returned_stat (np, p, 0); /* XXX Do we have to lock np? */ mutex_unlock (&np->lock); if (*newnp) mutex_lock (&(*newnp)->lock); @@ -603,14 +698,17 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np, } else *newnp = 0; - + + /* Notify the cache of the hit or miss. */ + enter_lookup_cache (dirhandle, dirlen, *newnp, name); + free (rpcbuf); - + return err; } /* Implement the netfs_attempt_mkdir callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_mkdir (struct iouser *cred, struct node *np, char *name, mode_t mode) @@ -630,32 +728,45 @@ netfs_attempt_mkdir (struct iouser *cred, struct node *np, mode &= ~S_ISUID; } + purge_lookup_cache (np, name, strlen (name)); + p = nfs_initialize_rpc (NFSPROC_MKDIR (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_string (p, name); p = xdr_encode_create_state (p, mode, owner); - + err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); - - p = lookup_fhandle (p, &newnp); - p = process_returned_stat (newnp, p, 1); - - /* Did we set the owner correctly? If not, try, but ignore failures. */ - if (!netfs_validate_stat (newnp, -1) && newnp->nn_stat.st_uid != owner) - netfs_attempt_chown (-1, newnp, owner, newnp->nn_stat.st_gid); - - /* We don't actually return this. */ - netfs_nput (newnp); - + { + err = nfs_error_trans (ntohl (*p)); + p++; + } + + if (!err) + { + p = xdr_decode_fhandle (p, &newnp); + p = process_returned_stat (newnp, p, 1); + + /* Did we set the owner correctly? If not, try, but ignore failures. */ + if (!netfs_validate_stat (newnp, (struct iouser *) -1) + && newnp->nn_stat.st_uid != owner) + netfs_attempt_chown ((struct iouser *) -1, newnp, owner, + newnp->nn_stat.st_gid); + + /* We don't actually return this. */ + netfs_nput (newnp); + } + free (rpcbuf); return err; } /* Implement the netfs_attempt_rmdir callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_rmdir (struct iouser *cred, struct node *np, char *name) @@ -663,28 +774,34 @@ netfs_attempt_rmdir (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - + /* Should we do the same sort of thing here as with attempt_unlink? */ + purge_lookup_cache (np, name, strlen (name)); + p = nfs_initialize_rpc (NFSPROC_RMDIR (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_string (p, name); - + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (protocol_version == 3) p = process_wcc_stat (np, p, !err); } - + free (rpcbuf); return err; } /* Implement the netfs_attempt_link callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_link (struct iouser *cred, struct node *dir, struct node *np, char *name, int excl) @@ -692,9 +809,16 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, int *p; void *rpcbuf; error_t err = 0; - + if (!excl) - return EOPNOTSUPP; /* XXX */ + { + /* We have no RPC available that will do an atomic replacement, + so we settle for second best; just doing an unlink and ignoring + any errors. */ + mutex_lock (&dir->lock); + netfs_attempt_unlink (cred, dir, name); + mutex_unlock (&dir->lock); + } /* If we have postponed a translator setting on an unlinked node, then here's where we set it, by creating the new node instead of @@ -707,21 +831,32 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, mutex_lock (&dir->lock); p = nfs_initialize_rpc (NFSPROC_LINK (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + { + mutex_unlock (&dir->lock); + return errno; + } + mutex_unlock (&dir->lock); - + mutex_lock (&np->lock); p = xdr_encode_fhandle (p, &np->nn->handle); mutex_unlock (&np->lock); - + mutex_lock (&dir->lock); + purge_lookup_cache (dir, name, strlen (name)); + p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); - + err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } mutex_unlock (&dir->lock); - + free (rpcbuf); break; @@ -730,9 +865,15 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, mutex_lock (&dir->lock); p = nfs_initialize_rpc (NFSPROC_SYMLINK (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + { + mutex_unlock (&dir->lock); + return errno; + } + p = xdr_encode_fhandle (p, &dir->nn->handle); mutex_unlock (&dir->lock); - + p = xdr_encode_string (p, name); mutex_lock (&np->lock); @@ -743,7 +884,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, free (rpcbuf); return err; } - + if (protocol_version == 2) { p = xdr_encode_string (p, np->nn->transarg.name); @@ -753,15 +894,18 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, { p = xdr_encode_sattr_stat (p, &np->nn_stat); p = xdr_encode_string (p, np->nn->transarg.name); - } + } mutex_unlock (&np->lock); mutex_lock (&dir->lock); + + purge_lookup_cache (dir, name, strlen (name)); err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); - + err = nfs_error_trans (ntohl (*p)); + p++; + if (protocol_version == 2 && !err) { free (rpcbuf); @@ -770,14 +914,22 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, fhandle, so we have to fetch one now. */ p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + { + mutex_unlock (&dir->lock); + return errno; + } p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); - + mutex_unlock (&dir->lock); - + err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } if (!err) { mutex_lock (&np->lock); @@ -810,7 +962,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, free (rpcbuf); break; - + case CHRDEV: case BLKDEV: case FIFO: @@ -825,10 +977,16 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + { + mutex_unlock (&dir->lock); + return errno; + } + p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); mutex_unlock (&dir->lock); - + mutex_lock (&np->lock); err = netfs_validate_stat (np, cred); if (err) @@ -837,30 +995,44 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, free (rpcbuf); return err; } - + p = xdr_encode_sattr_stat (p, &np->nn_stat); mutex_unlock (&np->lock); mutex_lock (&dir->lock); + purge_lookup_cache (dir, name, strlen (name)); + mutex_unlock (&dir->lock); /* XXX Should this really be after the + _lengthy_ (blocking) conduct_rpc? */ err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); - mutex_unlock (&dir->lock); - - mutex_lock (&np->lock); - p = recache_handle (p, np); - register_fresh_stat (np, p); - mutex_unlock (&np->lock); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } + + if (!err) + { + mutex_lock (&np->lock); + p = recache_handle (p, np); + register_fresh_stat (np, p); + mutex_unlock (&np->lock); + } + free (rpcbuf); } - else + else /* protocol_version != 2 */ { mutex_lock (&dir->lock); p = nfs_initialize_rpc (NFS3PROC_MKNOD, cred, 0, &rpcbuf, dir, -1); + if (! p) + { + mutex_unlock (&dir->lock); + return errno; + } p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); mutex_unlock (&dir->lock); - + mutex_lock (&np->lock); err = netfs_validate_stat (np, cred); if (err) @@ -869,21 +1041,22 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, free (rpcbuf); return err; } - *p++ = htonl (hurd_mode_to_nfs_type (np->nn_stat.st_mode)); + *(p++) = htonl (hurd_mode_to_nfs_type (np->nn_stat.st_mode)); p = xdr_encode_sattr_stat (p, &np->nn_stat); if (np->nn->dtrans == BLKDEV || np->nn->dtrans == CHRDEV) { -#define major(D) (((D)>>8) & 0xff) -#define minor(D) ((D) & 0xff) - *p++ = htonl (major (np->nn_stat.st_rdev)); - *p++ = htonl (minor (np->nn_stat.st_rdev)); + *(p++) = htonl (major (np->nn_stat.st_rdev)); + *(p++) = htonl (minor (np->nn_stat.st_rdev)); } mutex_unlock (&np->lock); - + + purge_lookup_cache (dir, name, strlen (name)); err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; + if (!err) { mutex_lock (&np->lock); @@ -902,7 +1075,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, if (err) return err; - + mutex_lock (&np->lock); if (np->nn->dtrans == SYMLINK) @@ -917,19 +1090,19 @@ netfs_attempt_link (struct iouser *cred, struct node *dir, np->nn->dead_dir = 0; np->nn->dead_name = 0; mutex_unlock (&np->lock); - + mutex_lock (&dir->lock); netfs_attempt_unlink ((struct iouser *)-1, dir, name); mutex_unlock (&dir->lock); } else mutex_unlock (&np->lock); - + return 0; } /* Implement the netfs_attempt_mkfile callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_mkfile (struct iouser *cred, struct node *dir, mode_t mode, struct node **newnp) @@ -941,16 +1114,20 @@ netfs_attempt_mkfile (struct iouser *cred, struct node *dir, /* This is the best we can do. */ name = malloc (50); + if (! name) + return ENOMEM; do { sprintf (name, ".nfstmpgnu.%d", n++); err = netfs_attempt_create_file (cred, dir, name, mode, newnp); if (err == EEXIST) - mutex_lock (&dir->lock); + mutex_lock (&dir->lock); /* XXX is this right? does create need this + and drop this on error? Doesn't look + like it. */ } while (err == EEXIST); - + if (err) { free (name); @@ -968,7 +1145,7 @@ netfs_attempt_mkfile (struct iouser *cred, struct node *dir, } /* Implement the netfs_attempt_create_file callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_create_file (struct iouser *cred, struct node *np, char *name, mode_t mode, struct node **newnp) @@ -1000,33 +1177,39 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np, } } + purge_lookup_cache (np, name, strlen (name)); + p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); p = xdr_encode_string (p, name); if (protocol_version == 3) { /* We happen to know this is where the XID is. */ int verf = *(int *)rpcbuf; - - *p++ = ntohl (EXCLUSIVE); + + *(p++) = ntohl (EXCLUSIVE); /* 8 byte verf */ - *p++ = ntohl (verf); + *(p++) = ntohl (verf); p++; } else p = xdr_encode_create_state (p, mode, owner); - + err = conduct_rpc (&rpcbuf, &p); mutex_unlock (&np->lock); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (!err) { - p = lookup_fhandle (p, newnp); + p = xdr_decode_fhandle (p, newnp); p = process_returned_stat (*newnp, p, 1); } if (err) @@ -1042,19 +1225,19 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np, mutex_lock (&(*newnp)->lock); } - if (*newnp && !netfs_validate_stat (*newnp, -1) + if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1) && (*newnp)->nn_stat.st_uid != owner) - netfs_attempt_chown (-1, *newnp, owner, (*newnp)->nn_stat.st_gid); + netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid); } else *newnp = 0; - + free (rpcbuf); return err; } /* Implement the netfs_attempt_unlink callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_unlink (struct iouser *cred, struct node *dir, char *name) @@ -1072,20 +1255,36 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, return err; } - /* See if there are any other users of this node than the + /* Restore the locks to sanity. */ + mutex_unlock (&np->lock); + mutex_lock (&dir->lock); + + /* Purge the cache of entries for this node, so that we don't + regard cache-held references as live. */ + purge_lookup_cache_node (np); + + /* See if there are any other users of this node than the one we just got; if so, we must give this file another link so that when we delete the one we are asked for it doesn't go away entirely. */ if (np->references > 1) { - char *newname; + char *newname = 0; int n = 0; + mutex_unlock (&dir->lock); + newname = malloc (50); - mutex_unlock (&np->lock); + if (! newname) + { + mutex_lock (&dir->lock); + netfs_nrele (np); /* XXX Is this the correct thing to do? */ + return ENOMEM; + } + do { - sprintf (newname, ".nfs%xgnu.%d", (int) np, n++); + sprintf (newname, ".nfs%txgnu.%d", (ptrdiff_t) np, n++); err = netfs_attempt_link (cred, dir, np, newname, 1); } while (err == EEXIST); @@ -1101,6 +1300,7 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, /* Write down what name we gave it; we'll delete this when all our uses vanish. */ mutex_lock (&np->lock); + if (np->nn->dead_dir) netfs_nrele (np->nn->dead_dir); netfs_nref (dir); @@ -1110,72 +1310,118 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, np->nn->dead_name = newname; if (np->nn->dtrans == NOT_POSSIBLE) np->nn->dtrans = POSSIBLE; + + netfs_nput (np); + mutex_lock (&dir->lock); } - netfs_nput (np); + else + netfs_nrele (np); - mutex_lock (&dir->lock); p = nfs_initialize_rpc (NFSPROC_REMOVE (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &dir->nn->handle); p = xdr_encode_string (p, name); - + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (protocol_version == 3) p = process_wcc_stat (dir, p, !err); } - + free (rpcbuf); return err; } /* Implement the netfs_attempt_rename callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_rename (struct iouser *cred, struct node *fromdir, - char *fromname, struct node *todir, char *toname, + char *fromname, struct node *todir, char *toname, int excl) { int *p; void *rpcbuf; error_t err; - + if (excl) - return EOPNOTSUPP; /* XXX */ + { + struct node *np; + + /* Just do a lookup/link/unlink sequence. */ + + mutex_lock (&fromdir->lock); + err = netfs_attempt_lookup (cred, fromdir, fromname, &np); + mutex_unlock (&fromdir->lock); + if (err) + return err; + + err = netfs_attempt_link (cred, todir, np, toname, 1); + netfs_nput (np); + if (err) + return err; + + mutex_lock (&fromdir->lock); + err = netfs_attempt_unlink (cred, fromdir, fromname); + mutex_unlock (&fromdir->lock); + + /* If the unlink failed, then back out the link */ + if (err) + { + mutex_lock (&todir->lock); + netfs_attempt_unlink (cred, todir, toname); + mutex_unlock (&todir->lock); + return err; + } + + return 0; + } mutex_lock (&fromdir->lock); + purge_lookup_cache (fromdir, fromname, strlen (fromname)); p = nfs_initialize_rpc (NFSPROC_RENAME (protocol_version), cred, 0, &rpcbuf, fromdir, -1); + if (! p) + { + mutex_unlock (&fromdir->lock); + return errno; + } + p = xdr_encode_fhandle (p, &fromdir->nn->handle); p = xdr_encode_string (p, fromname); mutex_unlock (&fromdir->lock); - + mutex_lock (&todir->lock); + purge_lookup_cache (todir, toname, strlen (toname)); p = xdr_encode_fhandle (p, &todir->nn->handle); p = xdr_encode_string (p, toname); mutex_unlock (&todir->lock); - + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); - if (protocol_version == 3) + err = nfs_error_trans (ntohl (*p)); + p++; + if (protocol_version == 3) /* XXX Should we add `&& !err' ? */ { mutex_lock (&fromdir->lock); p = process_wcc_stat (fromdir, p, !err); p = process_wcc_stat (todir, p, !err); } } - + free (rpcbuf); return err; } /* Implement the netfs_attempt_readlink callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_readlink (struct iouser *cred, struct node *np, char *buf) @@ -1189,15 +1435,19 @@ netfs_attempt_readlink (struct iouser *cred, struct node *np, strcpy (buf, np->nn->transarg.name); return 0; } - + p = nfs_initialize_rpc (NFSPROC_READLINK (protocol_version), cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); + err = nfs_error_trans (ntohl (*p)); + p++; if (protocol_version == 3) p = process_returned_stat (np, p, 0); if (!err) @@ -1209,16 +1459,16 @@ netfs_attempt_readlink (struct iouser *cred, struct node *np, } /* Implement the netfs_check_open_permissions callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_check_open_permissions (struct iouser *cred, struct node *np, int flags, int newnode) { int modes; - + if (newnode || (flags & (O_READ|O_WRITE|O_EXEC)) == 0) return 0; - + netfs_report_access (cred, np, &modes); if ((flags & (O_READ|O_WRITE|O_EXEC)) == (flags & modes)) return 0; @@ -1227,21 +1477,21 @@ netfs_check_open_permissions (struct iouser *cred, struct node *np, } /* Implement the netfs_report_access callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_report_access (struct iouser *cred, struct node *np, int *types) { error_t err; - + err = netfs_validate_stat (np, cred); if (err) return err; - + if (protocol_version == 2) { - /* Hope the server means the same thing be the bits as we do. */ + /* Hope the server means the same thing for the bits as we do. */ *types = 0; if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0) *types |= O_READ; @@ -1271,17 +1521,24 @@ netfs_report_access (struct iouser *cred, } p = nfs_initialize_rpc (NFS3PROC_ACCESS, cred, 0, &rpcbuf, np, -1); + if (! p) + return errno; + p = xdr_encode_fhandle (p, &np->nn->handle); - *p++ = htonl (ACCESS3_READ | write_check | execute_check); - + *(p++) = htonl (ACCESS3_READ | write_check | execute_check); + err = conduct_rpc (&rpcbuf, &p); if (!err) { - err = nfs_error_trans (ntohl (*p++)); - p = process_returned_stat (np, p, 0); + err = nfs_error_trans (ntohl (*p)); + p++; + p = process_returned_stat (np, p, 0); /* XXX Should this be + protected by the + if (!err) ? */ if (!err) { - ret = ntohl (*p++); + ret = ntohl (*p); + p++; *types = ((ret & ACCESS3_READ ? O_READ : 0) | (ret & write_check ? O_WRITE : 0) | (ret & execute_check ? O_EXEC : 0)); @@ -1292,7 +1549,7 @@ netfs_report_access (struct iouser *cred, } /* These definitions have unfortunate side effects, don't use them, - clever though they are. */ + clever though they are. */ #if 0 /* Implement the netfs_check_open_permissions callback as described in <hurd/netfs.h>. */ @@ -1303,7 +1560,7 @@ netfs_check_open_permissions (struct iouser *cred, struct node *np, char byte; error_t err; size_t len; - + /* Sun derived nfs client implementations attempt to reproduce the server's permission restrictions by hoping they look like Unix, and using that to give errors at open time. Sadly, that loses @@ -1321,17 +1578,17 @@ netfs_check_open_permissions (struct iouser *cred, struct node *np, && (flags & O_WRITE) == 0 && (flags & O_EXEC) == 0) return 0; - + err = netfs_validate_stat (np, cred); if (err) return err; - + switch (np->nn_stat.st_mode & S_IFMT) { /* Don't know how to check, so return provisional success. */ default: return 0; - + case S_IFREG: len = 1; err = netfs_attempt_read (cred, np, 0, &len, &byte); @@ -1340,16 +1597,16 @@ netfs_check_open_permissions (struct iouser *cred, struct node *np, if ((flags & O_READ) || (flags & O_EXEC)) return err; else - /* If we couldn't read a byte, but the user wasn't actually asking + /* If we couldn't read a byte, but the user wasn't actually asking for read, then we shouldn't inhibit the open now. */ return 0; } - + if (len != 1) /* The file is empty; reads are known to be OK, but writes can't be tested, so no matter what, return success. */ return 0; - + if (flags & O_WRITE) { err = netfs_attempt_write (cred, np, 0, &len, &byte); @@ -1370,22 +1627,25 @@ netfs_check_open_permissions (struct iouser *cred, struct node *np, return failure. Otherwise, succeed. */ p = nfs_initialize_rpc (NFSPROC_READDIR, cred, 0, &rpcbuf, np, -1); p = xdr_encode_fhandle (p, &np->nn->handle); - *p++ = 0; - *p++ = htonl (50); + *(p++) = 0; + *(p++) = htonl (50); err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } free (rpcbuf); - + if (err) return err; } return 0; } } - + /* Implement the netfs_report_access callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ void netfs_report_access (struct iouser *cred, struct node *np, @@ -1394,11 +1654,11 @@ netfs_report_access (struct iouser *cred, char byte; error_t err; size_t len; - + /* Much the same logic as netfs_check_open_permissions, except that here we err on the side of denying access, and that we always have to check everything. */ - + *types = 0; len = 1; @@ -1435,7 +1695,7 @@ netfs_report_access (struct iouser *cred, *BUFP to that buffer. *BUFP must be freed by the caller when no longer needed. If an error occurs, don't touch *BUFP and return the error code. Set BUFSIZEP to the amount of data used inside - *BUFP and TOTALENTRIES to the total number of entries copied. */ + *BUFP and TOTALENTRIES to the total number of entries copied. */ static error_t fetch_directory (struct iouser *cred, struct node *dir, void **bufp, size_t *bufsizep, int *totalentries) @@ -1452,7 +1712,11 @@ fetch_directory (struct iouser *cred, struct node *dir, int isnext; bufmalloced = read_size; + buf = malloc (bufmalloced); + if (! buf) + return ENOMEM; + bp = buf; cookie = 0; eof = 0; @@ -1463,65 +1727,80 @@ fetch_directory (struct iouser *cred, struct node *dir, /* Fetch new directory entries */ p = nfs_initialize_rpc (NFSPROC_READDIR (protocol_version), cred, 0, &rpcbuf, dir, -1); + if (! p) + { + free (buf); + return errno; + } + p = xdr_encode_fhandle (p, &dir->nn->handle); - *p++ = cookie; - *p++ = ntohl (read_size); + *(p++) = cookie; + *(p++) = ntohl (read_size); err = conduct_rpc (&rpcbuf, &p); if (!err) - err = nfs_error_trans (ntohl (*p++)); + { + err = nfs_error_trans (ntohl (*p)); + p++; + } if (err) { free (buf); return err; } - isnext = ntohl (*p++); - + isnext = ntohl (*p); + p++; + /* Now copy them one at a time. */ while (isnext) { ino_t fileno; int namlen; int reclen; - - fileno = ntohl (*p++); - namlen = ntohl (*p++); + + fileno = ntohl (*p); + p++; + namlen = ntohl (*p); + p++; /* There's a hidden +1 here for the null byte and -1 because d_name has a size of one already in the sizeof. */ reclen = sizeof (struct dirent) + namlen; reclen = (reclen + 3) & ~3; /* make it a multiple of four */ - + /* Expand buffer if necessary */ if (bp + reclen > buf + bufmalloced) { char *newbuf; - + newbuf = realloc (buf, bufmalloced *= 2); + assert (newbuf); if (newbuf != buf) bp = newbuf + (bp - buf); buf = newbuf; } - + /* Fill in new entry */ entry = (struct dirent *) bp; entry->d_fileno = fileno; entry->d_reclen = reclen; entry->d_type = DT_UNKNOWN; entry->d_namlen = namlen; - bcopy (p, entry->d_name, namlen); + memcpy (entry->d_name, p, namlen); entry->d_name[namlen] = '\0'; p += INTSIZE (namlen); bp = bp + entry->d_reclen; ++*totalentries; - - cookie = *p++; - isnext = ntohl (*p++); + + cookie = *(p++); + isnext = ntohl (*p); + p++; } - eof = ntohl (*p++); + eof = ntohl (*p); + p++; free (rpcbuf); } @@ -1531,9 +1810,9 @@ fetch_directory (struct iouser *cred, struct node *dir, return 0; } - + /* Implement the netfs_get_directs callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_get_dirents (struct iouser *cred, struct node *np, int entry, int nentries, char **data, @@ -1551,15 +1830,15 @@ netfs_get_dirents (struct iouser *cred, struct node *np, err = fetch_directory (cred, np, &buf, &our_bufsiz, &totalentries); if (err) return err; - + /* Allocate enough space to hold the maximum we might return. */ if (!bufsiz || bufsiz > our_bufsiz) allocsize = round_page (our_bufsiz); else allocsize = round_page (bufsiz); if (allocsize > *datacnt) - vm_allocate (mach_task_self (), (vm_address_t *)data, allocsize, 1); - + *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + /* Skip ahead to the correct entry. */ bp = buf; for (thisentry = 0; thisentry < entry;) @@ -1568,18 +1847,18 @@ netfs_get_dirents (struct iouser *cred, struct node *np, bp += entry->d_reclen; thisentry++; } - + /* Now copy them one at a time */ { int entries_copied; - - for (entries_copied = 0, userdp = *data; + + for (entries_copied = 0, userdp = *data; (nentries == -1 || entries_copied < nentries) && (!bufsiz || userdp - *data < bufsiz) && thisentry < totalentries;) { struct dirent *entry = (struct dirent *) bp; - bcopy (bp, userdp, entry->d_reclen); + memcpy (userdp, bp, entry->d_reclen); bp += entry->d_reclen; userdp += entry->d_reclen; entries_copied++; @@ -1587,34 +1866,23 @@ netfs_get_dirents (struct iouser *cred, struct node *np, } *amt = entries_copied; } - + free (buf); - /* If we allocated the buffer ourselves, but didn't use + /* If we allocated the buffer ourselves, but didn't use all the pages, free the extra. */ if (allocsize > *datacnt && round_page (userdp - *data) < round_page (allocsize)) - vm_deallocate (mach_task_self (), round_page (userdp), - round_page (allocsize) - round_page (userdp - *data)); + munmap ((caddr_t) round_page (userdp), + round_page (allocsize) - round_page (userdp - *data)); *datacnt = userdp - *data; return 0; } - -/* Implement the netfs_set_translator callback as described in - <hurd/netfs.h>. */ -error_t -netfs_set_translator (struct iouser *cred, - struct node *np, - char *argz, - size_t argzlen) -{ - return EOPNOTSUPP; -} /* Implement the netfs_attempt_mksymlink callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *np, @@ -1622,10 +1890,10 @@ netfs_attempt_mksymlink (struct iouser *cred, { if (np->nn->dtrans == NOT_POSSIBLE) return EOPNOTSUPP; - + if (np->nn->dtrans == SYMLINK) free (np->nn->transarg.name); - + np->nn->transarg.name = malloc (strlen (arg) + 1); strcpy (np->nn->transarg.name, arg); np->nn->dtrans = SYMLINK; @@ -1634,7 +1902,7 @@ netfs_attempt_mksymlink (struct iouser *cred, } /* Implement the netfs_attempt_mkdev callback as described in - <hurd/netfs.h>. */ + <hurd/netfs.h>. */ error_t netfs_attempt_mkdev (struct iouser *cred, struct node *np, @@ -1643,10 +1911,10 @@ netfs_attempt_mkdev (struct iouser *cred, { if (np->nn->dtrans == NOT_POSSIBLE) return EOPNOTSUPP; - + if (np->nn->dtrans == SYMLINK) free (np->nn->transarg.name); - + np->nn->transarg.indexes = indexes; if (type == S_IFBLK) np->nn->dtrans = BLKDEV; @@ -1655,5 +1923,3 @@ netfs_attempt_mkdev (struct iouser *cred, np->nn->stat_updated = 0; return 0; } - - diff --git a/nfs/pager.c b/nfs/pager.c deleted file mode 100644 index b511429b..00000000 --- a/nfs/pager.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - Written by Michael I. Bushnell, p/BSG. - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - The GNU Hurd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ - - -#include "nfs.h" -#include <unistd.h> -#include <hurd/pager.h> -#include <netinet/in.h> -#include <string.h> - -struct user_pager_info -{ - struct node *np; - struct pager *p; - int max_prot; -}; - -struct pager_cache_rec -{ - struct pager_cache_rec *next; - vm_offset_t offset; - struct pager *p; - time_t fetched; -}; - -static struct pager_cache_rec *pager_cache_recs; -static spin_lock_t pager_cache_rec_lock = SPIN_LOCK_INITIALIZER; -static spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER; -static struct port_bucket *pager_bucket; - -void -register_new_page (struct pager *p, vm_offset_t offset) -{ - struct pager_cache_rec *pc; - - pc = malloc (sizeof (struct pager_cache_rec)); - pc->offset = offset; - pc->p = p; - ports_port_ref (p); - pc->fetched = mapped_time->seconds; - - spin_lock (&pager_cache_rec_lock); - pc->next = pager_cache_recs; - pager_cache_recs = pc; - spin_unlock (&pager_cache_rec_lock); -} - -any_t -flush_pager_cache_thread (any_t foo2) -{ - struct pager_cache_rec *pc, *next, **ppc, *list; - - for (;;) - { - sleep (1); - - /* Dequeue from the main list and queue locally the recs - for expired pages. */ - list = 0; - spin_lock (&pager_cache_rec_lock); - for (pc = pager_cache_recs, ppc = &pager_cache_recs; - pc; - ppc = &pc->next, pc = next) - { - next = pc->next; - if (mapped_time->seconds - pc->fetched > cache_timeout) - { - *ppc = pc->next; - pc->next = list; - list = pc; - } - } - spin_unlock (&pager_cache_rec_lock); - - /* And now, one at a time, expire them */ - for (pc = list; pc; pc = next) - { - pager_return_some (pc->p, pc->offset, vm_page_size, 0); - next = pc->next; - ports_port_deref (pc->p); - free (pc); - } - } -} - -error_t -pager_read_page (struct user_pager_info *pager, - vm_offset_t page, - vm_address_t *buf, - int *writelock) -{ - error_t err; - int *p; - void *rpcbuf; - struct node *np; - size_t amt, thisamt, trans_len; - void *data; - off_t offset; - - np = pager->np; - - mutex_lock (&np->lock); - - vm_allocate (mach_task_self (), buf, vm_page_size, 1); - data = (char *) *buf; - amt = vm_page_size; - offset = page; - - while (amt) - { - thisamt = amt; - if (thisamt > read_size) - thisamt = read_size; - - p = nfs_initialize_rpc (NFSPROC_READ, (struct iouser *)-1, 0, - &rpcbuf, np, -1); - p = xdr_encode_fhandle (p, &np->nn->handle); - *p++ = htonl (offset); - *p++ = htonl (vm_page_size); - *p++ = 0; - - err = conduct_rpc (&rpcbuf, &p); - if (!err) - err = nfs_error_trans (ntohl (*p++)); - if (err) - { - mutex_unlock (&np->lock); - free (rpcbuf); - vm_deallocate (mach_task_self (), *buf, vm_page_size); - return err; - } - - p = register_fresh_stat (np, p); - trans_len = ntohl (*p++); - if (trans_len > thisamt) - trans_len = thisamt; /* ??? */ - - bcopy (p, data, trans_len); - - free (rpcbuf); - - data += trans_len; - offset += trans_len; - amt -= trans_len; - - /* If we got a short count, we're all done. */ - if (trans_len < thisamt) - break; - } - - register_new_page (pager->p, page); - mutex_unlock (&np->lock); - return 0; -} - - -error_t -pager_write_page (struct user_pager_info *pager, - vm_offset_t page, - vm_address_t buf) -{ - int *p; - void *rpcbuf; - error_t err; - size_t amt, thisamt; - off_t offset; - struct node *np; - void *data; - - np = pager->np; - mutex_lock (&np->lock); - - amt = vm_page_size; - offset = page; - data = (void *) buf; - - while (amt) - { - thisamt = amt; - if (amt > write_size) - amt = write_size; - - p = nfs_initialize_rpc (NFSPROC_WRITE, (struct iouser *) -1, - amt, &rpcbuf, np, -1); - p = xdr_encode_fhandle (p, &np->nn->handle); - *p++ = 0; - *p++ = htonl (offset); - *p++ = 0; - p = xdr_encode_data (p, data, thisamt); - - err = conduct_rpc (&rpcbuf, &p); - if (!err) - err = nfs_error_trans (ntohl (*p++)); - if (err) - { - free (rpcbuf); - vm_deallocate (mach_task_self (), buf, vm_page_size); - return err; - } - register_fresh_stat (np, p); - free (rpcbuf); - amt -= thisamt; - data += thisamt; - offset += thisamt; - } - - vm_deallocate (mach_task_self (), buf, vm_page_size); - mutex_unlock (&np->lock); - return 0; -} - -error_t -pager_unlock_page (struct user_pager_info *pager, - vm_offset_t address) -{ - abort (); -} - -error_t -pager_report_extent (struct user_pager_info *pager, - vm_address_t *offset, - vm_size_t *size) -{ - struct node *np; - error_t err; - - np = pager->np; - mutex_lock (&np->lock); - - err = netfs_validate_stat (np, 0); - if (!err) - *size = round_page (np->nn_stat.st_size); - mutex_unlock (&np->lock); - return err; -} - -void -pager_clear_user_data (struct user_pager_info *upi) -{ - spin_lock (&node2pagelock); - if (upi->np->nn->fileinfo == upi) - upi->np->nn->fileinfo = 0; - spin_unlock (&node2pagelock); - netfs_nrele (upi->np); - free (upi); -} - -void -pager_dropweak (struct user_pager_info *upi) -{ - abort (); -} - -mach_port_t -netfs_get_filemap (struct node *np, vm_prot_t prot) -{ - struct user_pager_info *upi; - mach_port_t right; - - spin_lock (&node2pagelock); - do - if (!np->nn->fileinfo) - { - upi = malloc (sizeof (struct user_pager_info)); - upi->np = np; - netfs_nref (np); - upi->max_prot = prot; - upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_NONE); - np->nn->fileinfo = upi; - right = pager_get_port (np->nn->fileinfo->p); - ports_port_deref (np->nn->fileinfo->p); - } - else - { - np->nn->fileinfo->max_prot |= prot; - /* Because NP->dn->fileinfo->p is not a real reference, - this might be nearly deallocated. If that's so, then - the port right will be null. In that case, clear here - and loop. The deallocation will complete separately. */ - right = pager_get_port (np->nn->fileinfo->p); - if (right == MACH_PORT_NULL) - np->nn->fileinfo = 0; - } - while (right == MACH_PORT_NULL); - - spin_unlock (&node2pagelock); - - mach_port_insert_right (mach_task_self (), right, right, - MACH_MSG_TYPE_MAKE_SEND); - return right; -} - -void -drop_pager_softrefs (struct node *np) -{ - struct user_pager_info *upi; - - spin_lock (&node2pagelock); - upi = np->nn->fileinfo; - if (upi) - ports_port_ref (upi->p); - spin_unlock (&node2pagelock); - - if (upi) - { - pager_change_attributes (upi->p, 0, MEMORY_OBJECT_COPY_NONE, 0); - ports_port_deref (upi->p); - } -} - -void -allow_pager_softrefs (struct node *np) -{ - struct user_pager_info *upi; - - spin_lock (&node2pagelock); - upi = np->nn->fileinfo; - if (upi) - ports_port_ref (upi->p); - spin_unlock (&node2pagelock); - - if (upi) - { - pager_change_attributes (upi->p, 1, MEMORY_OBJECT_COPY_NONE, 0); - ports_port_deref (upi->p); - } -} - -void -block_caching () -{ - error_t block_cache (void *arg) - { - struct pager *p = arg; - pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_NONE, 1); - return 0; - } - ports_bucket_iterate (pager_bucket, block_cache); -} - -void -enable_caching () -{ - error_t enable_cache (void *arg) - { - struct pager *p = arg; - struct user_pager_info *upi = pager_get_upi (p); - - pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_NONE, 0); - return 0; - } - - ports_bucket_iterate (pager_bucket, enable_cache); -} - -int -netfs_pager_users () -{ - int npagers = ports_count_bucket (pager_bucket); - - if (!npagers) - return 0; - - block_caching (); - /* Give it a sec; the kernel doesn't issue the shutdown right away */ - sleep (1); - npagers = ports_count_bucket (pager_bucket); - if (!npagers) - return 0; - - enable_caching (); - - ports_enable_bucket (pager_bucket); -} - -vm_prot_t -netfs_max_user_pager_prot () -{ - vm_prot_t max_prot; - int npagers = ports_count_bucket (pager_bucket); - - if (npagers) - { - error_t add_pager_max_prot (void *v_p) - { - struct pager *p = v_p; - struct user_pager_info *upi = pager_get_upi (p); - max_prot |= upi->max_prot; - return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); - } - - block_caching (); - sleep (1); - - ports_bucket_iterate (pager_bucket, add_pager_max_prot); - enable_caching (); - } - - ports_enable_bucket (pager_bucket); - return max_prot; -} - -void -netfs_shutdown_pager () -{ - error_t shutdown_one (void *arg) - { - pager_shutdown ((struct pager *) arg); - return 0; - } - - ports_bucket_iterate (pager_bucket, shutdown_one); -} - -void -netfs_sync_everything (int wait) -{ - error_t sync_one (void *arg) - { - pager_sync ((struct pager *) arg, wait); - return 0; - } - ports_bucket_iterate (pager_bucket, sync_one); -} - -void -pager_initialize (void) -{ - pager_bucket = ports_create_bucket (); - cthread_detach (cthread_fork (flush_pager_cache_thread, 0)); - @@ -1,5 +1,5 @@ -/* SunRPC management for NFS client - Copyright (C) 1994, 1995, 1996 Free Software Foundation +/* rpc.c - SunRPC management for NFS client. + Copyright (C) 1994, 1995, 1996, 1997, 2002 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -17,10 +17,10 @@ #include "nfs.h" -/* Needed in order to get the RPC header files to include correctly */ +/* Needed in order to get the RPC header files to include correctly. */ #undef TRUE #undef FALSE -#define malloc spoiufasdf /* Avoid bogus definition in rpc/types.h */ +#define malloc spoiufasdf /* Avoid bogus definition in rpc/types.h. */ #include <rpc/types.h> #include <rpc/xdr.h> @@ -28,35 +28,36 @@ #include <rpc/rpc_msg.h> #include <rpc/auth_unix.h> -#undef malloc /* Get rid protection. */ +#undef malloc /* Get rid of the sun block. */ #include <netinet/in.h> #include <assert.h> #include <errno.h> +#include <error.h> #include <unistd.h> #include <stdio.h> -/* One of these exists for each pending RPC. */ +/* One of these exists for each pending RPC. */ struct rpc_list { struct rpc_list *next, **prevp; void *reply; }; -/* A list of all the pending RPCs. */ +/* A list of all pending RPCs. */ static struct rpc_list *outstanding_rpcs; /* Wake up this condition when an outstanding RPC has received a reply - or we should check for timeouts. */ + or we should check for timeouts. */ static struct condition rpc_wakeup = CONDITION_INITIALIZER; -/* Lock the global data and the REPLY fields of outstanding RPC's. */ +/* Lock the global data and the REPLY fields of outstanding RPC's. */ static struct mutex outstanding_lock = MUTEX_INITIALIZER; -/* Generate and return a new transaction ID. */ -static int +/* Generate and return a new transaction ID. */ +static inline int generate_xid () { static int nextxid; @@ -67,22 +68,31 @@ generate_xid () return nextxid++; } -/* Set up an RPC for procdeure RPC_PROC, for talking to the server +/* Set up an RPC for procdeure RPC_PROC for talking to the server PROGRAM of version VERSION. Allocate storage with malloc and point *BUF at it; caller must free this when done. Allocate at least LEN - bytes more than the usual amount for an RPC. Initialize the RPC - credential structure with UID, GID, and SECOND_GID. (Any of those - may be -1 to indicate that it does not apply; exactly or two of UID - and GID must be -1, however.) */ + bytes more than the usual amount for the RPC. Initialize the RPC + credential structure with UID, GID, and SECOND_GID; any of these + may be -1 to indicate that it does not apply, however, exactly zero + or two of UID and GID must be -1. The returned address is a pointer + to the start of the payload. If NULL is returned, an error occurred + and the code is set in errno. */ int * initialize_rpc (int program, int version, int rpc_proc, size_t len, void **bufp, uid_t uid, gid_t gid, gid_t second_gid) { - void *buf = malloc (len + 1024); + void *buf; int *p, *lenaddr; struct rpc_list *hdr; + buf = malloc (len + 1024); + if (! buf) + { + errno = ENOMEM; + return NULL; + } + /* First the struct rpc_list bit. */ hdr = buf; hdr->reply = 0; @@ -90,49 +100,53 @@ initialize_rpc (int program, int version, int rpc_proc, p = buf + sizeof (struct rpc_list); /* RPC header */ - *p++ = htonl (generate_xid ()); - *p++ = htonl (CALL); - *p++ = htonl (RPC_MSG_VERSION); - *p++ = htonl (program); - *p++ = htonl (version); - *p++ = htonl (rpc_proc); + *(p++) = htonl (generate_xid ()); + *(p++) = htonl (CALL); + *(p++) = htonl (RPC_MSG_VERSION); + *(p++) = htonl (program); + *(p++) = htonl (version); + *(p++) = htonl (rpc_proc); assert ((uid == -1) == (gid == -1)); - if (uid != -1) + if (uid == -1) { - *p++ = htonl (AUTH_UNIX); + /* No authentication */ + *(p++) = htonl (AUTH_NONE); + *(p++) = 0; + } + else + { + /* Unixy authentication */ + *(p++) = htonl (AUTH_UNIX); + /* The length of the message. We do not yet know what this + is, so, just remember where we should put it when we know */ lenaddr = p++; - *p++ = htonl (mapped_time->seconds); + *(p++) = htonl (mapped_time->seconds); p = xdr_encode_string (p, hostname); - *p++ = htonl (uid); - *p++ = htonl (gid); - if (second_gid != -1) + *(p++) = htonl (uid); + *(p++) = htonl (gid); + if (second_gid == -1) + *(p++) = 0; + else { - *p++ = htonl (1); - *p++ = htonl (second_gid); + *(p++) = htonl (1); + *(p++) = htonl (second_gid); } - else - *p++ = 0; *lenaddr = htonl ((p - (lenaddr + 1)) * sizeof (int)); } - else - { - *p++ = htonl (AUTH_NULL); - *p++ = 0; - } /* VERF field */ - *p++ = htonl (AUTH_NULL); - *p++ = 0; + *(p++) = htonl (AUTH_NONE); + *(p++) = 0; *bufp = buf; return p; } -/* Remove HDR from the list of pending RPC's. rpc_list_lock must be - held */ -static void +/* Remove HDR from the list of pending RPC's. The rpc_list's lock + (OUTSTANDING_LOCK) must be held. */ +static inline void unlink_rpc (struct rpc_list *hdr) { *hdr->prevp = hdr->next; @@ -140,12 +154,24 @@ unlink_rpc (struct rpc_list *hdr) hdr->next->prevp = hdr->prevp; } +/* Insert HDR at the head of the LIST. The rpc_list's lock + (OUTSTANDING_LOCK) must be held. */ +static inline void +link_rpc (struct rpc_list **list, struct rpc_list *hdr) +{ + hdr->next = *list; + if (hdr->next) + hdr->next->prevp = &hdr->next; + hdr->prevp = list; + *list = hdr; +} + /* Send the specified RPC message. *RPCBUF is the initialized buffer - from a previous initialize_rpc call; *PP points past the filled - in args. Set *PP to the address of the reply contents themselves. - The user will be expected to free *RPCBUF (which will have changed) - when done with the reply contents. The old value of *RPCBUF will - be freed by this routine. */ + from a previous initialize_rpc call; *PP, the payload, points past + the filledin args. Set *PP to the address of the reply contents + themselves. The user will be expected to free *RPCBUF (which will + have changed) when done with the reply contents. The old value of + *RPCBUF will be freed by this routine. */ error_t conduct_rpc (void **rpcbuf, int **pp) { @@ -162,18 +188,13 @@ conduct_rpc (void **rpcbuf, int **pp) mutex_lock (&outstanding_lock); - /* Link it in */ - hdr->next = outstanding_rpcs; - if (hdr->next) - hdr->next->prevp = &hdr->next; - hdr->prevp = &outstanding_rpcs; - outstanding_rpcs = hdr; + link_rpc (&outstanding_rpcs, hdr); xid = * (int *) (*rpcbuf + sizeof (struct rpc_list)); do { - /* If we've sent enough, give up */ + /* If we've sent enough, give up. */ if (mounted_soft && ntransmit == soft_retries) { unlink_rpc (hdr); @@ -181,7 +202,7 @@ conduct_rpc (void **rpcbuf, int **pp) return ETIMEDOUT; } - /* Issue the RPC */ + /* Issue the RPC. */ lasttrans = mapped_time->seconds; ntransmit++; nc = (void *) *pp - *rpcbuf - sizeof (struct rpc_list); @@ -195,7 +216,7 @@ conduct_rpc (void **rpcbuf, int **pp) else assert (cc == nc); - /* Wait for reply */ + /* Wait for reply. */ cancel = 0; while (!hdr->reply && (mapped_time->seconds - lasttrans < timeout) @@ -209,9 +230,12 @@ conduct_rpc (void **rpcbuf, int **pp) return EINTR; } + /* hdr->reply will have been filled in by rpc_receive_thread, + if it has been filled in, then the rpc has been fulfilled, + otherwise, retransmit and continue to wait. */ if (!hdr->reply) { - timeout *=2; + timeout *= 2; if (timeout > max_transmit_timeout) timeout = max_transmit_timeout; } @@ -220,32 +244,36 @@ conduct_rpc (void **rpcbuf, int **pp) mutex_unlock (&outstanding_lock); - /* Switch to the reply buffer. */ + /* Switch to the reply buffer. */ *rpcbuf = hdr->reply; free (hdr); - /* Process the reply, dissecting errors. When we're done, set *PP to - the rpc return contents, if there is no error. */ + /* Process the reply, dissecting errors. When we're done and if + there is no error, set *PP to the rpc return contents. */ p = (int *) *rpcbuf; + /* If the transmition id does not match that in the message, + something strange happened in rpc_receive_thread. */ assert (*p == xid); p++; - switch (ntohl (*p++)) + switch (ntohl (*p)) { default: err = EBADRPC; break; case REPLY: - switch (ntohl (*p++)) + p++; + switch (ntohl (*p)) { default: err = EBADRPC; break; case MSG_DENIED: - switch (ntohl (*p++)) + p++; + switch (ntohl (*p)) { default: err = EBADRPC; @@ -256,7 +284,8 @@ conduct_rpc (void **rpcbuf, int **pp) break; case AUTH_ERROR: - switch (ntohl (*p++)) + p++; + switch (ntohl (*p)) { case AUTH_BADCRED: case AUTH_REJECTEDCRED: @@ -278,13 +307,15 @@ conduct_rpc (void **rpcbuf, int **pp) break; case MSG_ACCEPTED: + p++; - /* Process VERF field. */ - p++; /* skip verf type */ - n = ntohl (*p++); /* size of verf */ - p += INTSIZE (n); /* skip verf itself */ + /* Process VERF field. */ + p++; /* Skip verf type. */ + n = ntohl (*p); /* Size of verf. */ + p++; + p += INTSIZE (n); /* Skip verf itself. */ - switch (ntohl (*p++)) + switch (ntohl (*p)) { default: case GARBAGE_ARGS: @@ -304,6 +335,7 @@ conduct_rpc (void **rpcbuf, int **pp) break; case SUCCESS: + p++; *pp = p; err = 0; break; @@ -315,7 +347,8 @@ conduct_rpc (void **rpcbuf, int **pp) return err; } -/* Dedicated thread to wakeup rpc_wakeup once a second. */ +/* Dedicated thread to signal those waiting on rpc_wakeup + once a second. */ void timeout_service_thread () { @@ -329,50 +362,56 @@ timeout_service_thread () } /* Dedicate thread to receive RPC replies, register them on the queue - of pending wakeups, and deal appropriately. */ + of pending wakeups, and deal appropriately. */ void rpc_receive_thread () { - int cc; void *buf; - struct rpc_list *r; - int xid; + + /* Allocate a receive buffer. */ + buf = malloc (1024 + read_size); + assert (buf); while (1) { - buf = malloc (1024 + read_size); - - do - { - cc = read (main_udp_socket, buf, 1024 + read_size); - if (cc == -1) - { - perror ("nfs read"); - r = 0; + int cc = read (main_udp_socket, buf, 1024 + read_size); + if (cc == -1) + { + error (0, errno, "nfs read"); + continue; + } + else + { + struct rpc_list *r; + int xid = *(int *)buf; + + mutex_lock (&outstanding_lock); + + /* Find the rpc that we just fulfilled. */ + for (r = outstanding_rpcs; r; r = r->next) + { + if (* (int *) &r[1] == xid) + { + unlink_rpc (r); + r->reply = buf; + condition_broadcast (&rpc_wakeup); + break; + } } - else +#if 0 + if (! r) + fprintf (stderr, "NFS dropping reply xid %d\n", xid); +#endif + mutex_unlock (&outstanding_lock); + + /* If r is not null then we had a message from a pending + (i.e. known) rpc. Thus, it was fulfilled and if we want + to get another request, a new buffer is needed. */ + if (r) { - xid = *(int *)buf; - mutex_lock (&outstanding_lock); - for (r = outstanding_rpcs; r; r = r->next) - { - if (* (int *) &r[1] == xid) - { - /* Remove it from the list */ - *r->prevp = r->next; - if (r->next) - r->next->prevp = r->prevp; - - r->reply = buf; - condition_broadcast (&rpc_wakeup); - break; - } - } - if (!r) - fprintf (stderr, "NFS dropping reply xid %d\n", xid); - mutex_unlock (&outstanding_lock); + buf = malloc (1024 + read_size); + assert (buf); } - } - while (!r); + } } } diff --git a/nfs/storage-info.c b/nfs/storage-info.c new file mode 100644 index 00000000..7427b3d8 --- /dev/null +++ b/nfs/storage-info.c @@ -0,0 +1,104 @@ +/* file_get_storage_info RPC for NFS client filesystem + Copyright (C) 2001,02 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "nfs.h" +#include <hurd/netfs.h> +#include <stdio.h> + +error_t +netfs_file_get_storage_info (struct iouser *cred, + struct node *np, + mach_port_t **ports, + mach_msg_type_name_t *ports_type, + mach_msg_type_number_t *num_ports, + int **ints, + mach_msg_type_number_t *num_ints, + off_t **offsets, + mach_msg_type_number_t *num_offsets, + char **data, + mach_msg_type_number_t *data_len) +{ + int name_len, fhpos; + error_t err; + + inline int fmt (size_t buflen) + { + return snprintf (*data, buflen, + "nfsv%u://%s:%u/%n%*c?rsize=%u&wsize=%u", + protocol_version, mounted_hostname, mounted_nfs_port, + &fhpos, (int) (np->nn->handle.size * 2), + 'X', /* filled below */ + read_size, write_size); + } + + /* We return the file size, so make sure we have it up to date now. */ + err = netfs_validate_stat (np, cred); + if (err) + return err; + + /* Format the name, and then do it again if the buffer was too short. */ + name_len = fmt (*data_len); + if (name_len < 0) + return errno; + ++name_len; /* Include the terminating null. */ + if (name_len <= *data_len) + *data_len = name_len; + else + { + *data = mmap (0, name_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*data == MAP_FAILED) + return errno; + *data_len = fmt (name_len) + 1; + assert (*data_len == name_len); + } + + /* Now fill in the file handle data in hexadecimal. */ + { + static const char hexdigits[] = "0123456789abcdef"; + size_t i; + for (i = 0; i < np->nn->handle.size; ++i) + { + (*data)[fhpos++] = hexdigits[(uint8_t)np->nn->handle.data[i] >> 4]; + (*data)[fhpos++] = hexdigits[(uint8_t)np->nn->handle.data[i] & 0xf]; + } + } + + /* Now fill in the rest of the canonical-form storage-info data, which + just describes a single run of the file's size, a block-size of one + byte, and our URL as the name for the network store type. */ + + *num_ports = 0; + *ports_type = MACH_MSG_TYPE_COPY_SEND; + + assert (*num_offsets >= 2); /* mig always gives us some */ + *num_offsets = 2; + (*offsets)[0] = 0; + (*offsets)[1] = np->nn_stat.st_size; + + assert (*num_ints >= 6); /* mig always gives us some */ + *num_ints = 1; + (*ints)[0] = STORAGE_NETWORK; + (*ints)[1] = 0; /* XXX readonly if we supported it */ + (*ints)[2] = 1; /* block size */ + (*ints)[3] = 1; /* 1 run in offsets list */ + (*ints)[4] = name_len; + (*ints)[5] = 0; /* misc len */ + + return 0; +} |