From 0fb0ca67e45e134e69ffad7398eea114f4b4a044 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 29 Apr 2008 02:35:48 -0400 Subject: [PATCH] --- yaml --- r: 101978 b: refs/heads/master c: 26d46867b7d27f68a446b073dac7817721ae4c8f h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/acpi/scan.c | 56 +- trunk/fs/Kconfig | 136 +-- trunk/fs/lockd/clntproc.c | 8 +- trunk/fs/lockd/svc4proc.c | 2 - trunk/fs/lockd/svclock.c | 7 +- trunk/fs/lockd/svcproc.c | 2 - trunk/fs/nfs/callback.c | 34 +- trunk/fs/nfs/client.c | 13 +- trunk/fs/nfs/dir.c | 88 +- trunk/fs/nfs/direct.c | 4 +- trunk/fs/nfs/file.c | 155 +--- trunk/fs/nfs/inode.c | 79 +- trunk/fs/nfs/internal.h | 1 - trunk/fs/nfs/iostat.h | 119 ++- trunk/fs/nfs/nfs3acl.c | 9 +- trunk/fs/nfs/nfs3proc.c | 275 +++--- trunk/fs/nfs/nfs4proc.c | 265 +++--- trunk/fs/nfs/nfs4state.c | 2 + trunk/fs/nfs/nfsroot.c | 10 +- trunk/fs/nfs/proc.c | 28 +- trunk/fs/nfs/super.c | 882 ++++++-------------- trunk/fs/nfs/write.c | 322 +++---- trunk/fs/nfsd/nfs4callback.c | 2 +- trunk/include/linux/blkdev.h | 3 - trunk/include/linux/inet.h | 7 - trunk/include/linux/nfs_fs.h | 10 - trunk/include/linux/nfs_iostat.h | 119 --- trunk/include/linux/nfs_page.h | 9 +- trunk/include/linux/nfs_xdr.h | 3 +- trunk/include/linux/sunrpc/clnt.h | 7 +- trunk/include/linux/sunrpc/sched.h | 1 + trunk/net/sunrpc/auth_gss/auth_gss.c | 27 +- trunk/net/sunrpc/auth_gss/gss_krb5_mech.c | 4 +- trunk/net/sunrpc/auth_gss/gss_spkm3_mech.c | 4 +- trunk/net/sunrpc/auth_gss/gss_spkm3_token.c | 2 +- trunk/net/sunrpc/auth_unix.c | 2 +- trunk/net/sunrpc/clnt.c | 161 ++-- trunk/net/sunrpc/rpcb_clnt.c | 356 ++------ trunk/net/sunrpc/sched.c | 23 +- trunk/net/sunrpc/xprt.c | 9 +- trunk/net/sunrpc/xprtsock.c | 2 + 42 files changed, 1278 insertions(+), 1972 deletions(-) delete mode 100644 trunk/include/linux/nfs_iostat.h diff --git a/[refs] b/[refs] index 219d2597ae08..8f4369b6b463 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d442cc44c0db56e84ef6aa244a88427d2efe06cd +refs/heads/master: 26d46867b7d27f68a446b073dac7817721ae4c8f diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index 6d85289f1c12..9a84ed250d9f 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include /* for acpi_ex_eisa_id_to_string() */ @@ -92,17 +93,37 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); -static int acpi_eject_operation(acpi_handle handle, int lockable) +static int acpi_bus_hot_remove_device(void *context) { + struct acpi_device *device; + acpi_handle handle = context; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; - /* - * TBD: evaluate _PS3? - */ + if (acpi_bus_get_device(handle, &device)) + return 0; - if (lockable) { + if (!device) + return 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Hot-removing device %s...\n", device->dev.bus_id)); + + + if (acpi_bus_trim(device, 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Removing device failed\n")); + return -1; + } + + /* power off device */ + status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Power-off device failed\n")); + + if (device->flags.lockable) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -118,24 +139,19 @@ static int acpi_eject_operation(acpi_handle handle, int lockable) /* * TBD: _EJD support. */ - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - return (-ENODEV); - } + if (ACPI_FAILURE(status)) + return -ENODEV; - return (0); + return 0; } static ssize_t acpi_eject_store(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int result; int ret = count; - int islockable; acpi_status status; - acpi_handle handle; acpi_object_type type = 0; struct acpi_device *acpi_device = to_acpi_device(d); @@ -154,17 +170,9 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, goto err; } - islockable = acpi_device->flags.lockable; - handle = acpi_device->handle; - - result = acpi_bus_trim(acpi_device, 1); - - if (!result) - result = acpi_eject_operation(handle, islockable); - - if (result) { - ret = -EBUSY; - } + /* remove the device in another thread to fix the deadlock issue */ + ret = kernel_thread(acpi_bus_hot_remove_device, + acpi_device->handle, SIGCHLD); err: return ret; } diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index 84ab76a206a0..313b2e06ded5 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -1544,6 +1544,10 @@ config UFS_FS The recently released UFS2 variant (used in FreeBSD 5.x) is READ-ONLY supported. + If you only intend to mount files from some other Unix over the + network using NFS, you don't need the UFS file system support (but + you need NFS file system support obviously). + Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes (and even other operating systems) is given by the tar program ("man @@ -1583,7 +1587,6 @@ menuconfig NETWORK_FILESYSTEMS Say Y here to get to see options for network filesystems and filesystem-related networking code, such as NFS daemon and RPCSEC security modules. - This option alone does not add any kernel code. If you say N, all options in this submenu will be skipped and @@ -1592,92 +1595,76 @@ menuconfig NETWORK_FILESYSTEMS if NETWORK_FILESYSTEMS config NFS_FS - tristate "NFS client support" + tristate "NFS file system support" depends on INET select LOCKD select SUNRPC select NFS_ACL_SUPPORT if NFS_V3_ACL help - Choose Y here if you want to access files residing on other - computers using Sun's Network File System protocol. To compile - this file system support as a module, choose M here: the module - will be called nfs. + If you are connected to some other (usually local) Unix computer + (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing + on that computer (the NFS server) using the Network File Sharing + protocol, say Y. "Mounting files" means that the client can access + the files with usual UNIX commands as if they were sitting on the + client's hard disk. For this to work, the server must run the + programs nfsd and mountd (but does not need to have NFS file system + support enabled in its kernel). NFS is explained in the Network + Administrator's Guide, available from + , on its man page: "man + nfs", and in the NFS-HOWTO. - To mount file systems exported by NFS servers, you also need to - install the user space mount.nfs command which can be found in - the Linux nfs-utils package, available from http://linux-nfs.org/. - Information about using the mount command is available in the - mount(8) man page. More detail about the Linux NFS client - implementation is available via the nfs(5) man page. + A superior but less widely used alternative to NFS is provided by + the Coda file system; see "Coda file system support" below. - Below you can choose which versions of the NFS protocol are - available in the kernel to mount NFS servers. Support for NFS - version 2 (RFC 1094) is always available when NFS_FS is selected. + If you say Y here, you should have said Y to TCP/IP networking also. + This option would enlarge your kernel by about 27 KB. - To configure a system which mounts its root file system via NFS - at boot time, say Y here, select "Kernel level IP - autoconfiguration" in the NETWORK menu, and select "Root file - system on NFS" below. You cannot compile this file system as a - module in this case. + To compile this file system support as a module, choose M here: the + module will be called nfs. - If unsure, say N. + If you are configuring a diskless machine which will mount its root + file system over NFS at boot time, say Y here and to "Kernel + level IP autoconfiguration" above and to "Root file system on NFS" + below. You cannot compile this driver as a module in this case. + There are two packages designed for booting diskless machines over + the net: netboot, available from + , and Etherboot, + available from . + + If you don't know what all this is about, say N. config NFS_V3 - bool "NFS client support for NFS version 3" + bool "Provide NFSv3 client support" depends on NFS_FS help - This option enables support for version 3 of the NFS protocol - (RFC 1813) in the kernel's NFS client. + Say Y here if you want your NFS client to be able to speak version + 3 of the NFS protocol. If unsure, say Y. config NFS_V3_ACL - bool "NFS client support for the NFSv3 ACL protocol extension" + bool "Provide client support for the NFSv3 ACL protocol extension" depends on NFS_V3 help - Some NFS servers support an auxiliary NFSv3 ACL protocol that - Sun added to Solaris but never became an official part of the - NFS version 3 protocol. This protocol extension allows - applications on NFS clients to manipulate POSIX Access Control - Lists on files residing on NFS servers. NFS servers enforce - ACLs on local files whether this protocol is available or not. - - Choose Y here if your NFS server supports the Solaris NFSv3 ACL - protocol extension and you want your NFS client to allow - applications to access and modify ACLs on files on the server. - - Most NFS servers don't support the Solaris NFSv3 ACL protocol - extension. You can choose N here or specify the "noacl" mount - option to prevent your NFS client from trying to use the NFSv3 - ACL protocol. + Implement the NFSv3 ACL protocol extension for manipulating POSIX + Access Control Lists. The server should also be compiled with + the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. If unsure, say N. config NFS_V4 - bool "NFS client support for NFS version 4 (EXPERIMENTAL)" + bool "Provide NFSv4 client support (EXPERIMENTAL)" depends on NFS_FS && EXPERIMENTAL select RPCSEC_GSS_KRB5 help - This option enables support for version 4 of the NFS protocol - (RFC 3530) in the kernel's NFS client. + Say Y here if you want your NFS client to be able to speak the newer + version 4 of the NFS protocol. - To mount NFS servers using NFSv4, you also need to install user - space programs which can be found in the Linux nfs-utils package, - available from http://linux-nfs.org/. + Note: Requires auxiliary userspace daemons which may be found on + http://www.citi.umich.edu/projects/nfsv4/ If unsure, say N. -config ROOT_NFS - bool "Root file system on NFS" - depends on NFS_FS=y && IP_PNP - help - If you want your system to mount its root file system via NFS, - choose Y here. This is common practice for managing systems - without local permanent storage. For details, read - . - - Most people say N here. - config NFSD tristate "NFS server support" depends on INET @@ -1759,6 +1746,20 @@ config NFSD_V4 If unsure, say N. +config ROOT_NFS + bool "Root file system on NFS" + depends on NFS_FS=y && IP_PNP + help + If you want your Linux box to mount its whole root file system (the + one containing the directory /) from some other computer over the + net via NFS (presumably because your box doesn't have a hard disk), + say Y. Read for + details. It is likely that in this case, you also want to say Y to + "Kernel level IP autoconfiguration" so that your box can discover + its network address at boot time. + + Most people say N here. + config LOCKD tristate @@ -1799,6 +1800,27 @@ config SUNRPC_XPRT_RDMA If unsure, say N. +config SUNRPC_BIND34 + bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" + depends on SUNRPC && EXPERIMENTAL + default n + help + RPC requests over IPv6 networks require support for larger + addresses when performing an RPC bind. Sun added support for + IPv6 addressing by creating two new versions of the rpcbind + protocol (RFC 1833). + + This option enables support in the kernel RPC client for + querying rpcbind servers via versions 3 and 4 of the rpcbind + protocol. The kernel automatically falls back to version 2 + if a remote rpcbind service does not support versions 3 or 4. + By themselves, these new versions do not provide support for + RPC over IPv6, but the new protocol versions are necessary to + support it. + + If unsure, say N to get traditional behavior (version 2 rpcbind + requests only). + config RPCSEC_GSS_KRB5 tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" depends on SUNRPC && EXPERIMENTAL diff --git a/trunk/fs/lockd/clntproc.c b/trunk/fs/lockd/clntproc.c index 1f6dc518505c..5df517b81f3f 100644 --- a/trunk/fs/lockd/clntproc.c +++ b/trunk/fs/lockd/clntproc.c @@ -224,9 +224,7 @@ void nlm_release_call(struct nlm_rqst *call) static void nlmclnt_rpc_release(void *data) { - lock_kernel(); nlm_release_call(data); - unlock_kernel(); } static int nlm_wait_on_grace(wait_queue_head_t *queue) @@ -432,7 +430,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) * Report the conflicting lock back to the application. */ fl->fl_start = req->a_res.lock.fl.fl_start; - fl->fl_end = req->a_res.lock.fl.fl_end; + fl->fl_end = req->a_res.lock.fl.fl_start; fl->fl_type = req->a_res.lock.fl.fl_type; fl->fl_pid = 0; break; @@ -712,9 +710,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) die: return; retry_rebind: - lock_kernel(); nlm_rebind_host(req->a_host); - unlock_kernel(); retry_unlock: rpc_restart_call(task); } @@ -792,9 +788,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) /* Don't ever retry more than 3 times */ if (req->a_retries++ >= NLMCLNT_MAX_RETRIES) goto die; - lock_kernel(); nlm_rebind_host(req->a_host); - unlock_kernel(); rpc_restart_call(task); rpc_delay(task, 30 * HZ); } diff --git a/trunk/fs/lockd/svc4proc.c b/trunk/fs/lockd/svc4proc.c index 2e27176ff42f..385437e3387d 100644 --- a/trunk/fs/lockd/svc4proc.c +++ b/trunk/fs/lockd/svc4proc.c @@ -248,9 +248,7 @@ static void nlm4svc_callback_exit(struct rpc_task *task, void *data) static void nlm4svc_callback_release(void *data) { - lock_kernel(); nlm_release_call(data); - unlock_kernel(); } static const struct rpc_call_ops nlm4svc_callback_ops = { diff --git a/trunk/fs/lockd/svclock.c b/trunk/fs/lockd/svclock.c index 56a08ab9a4cb..81aca859bfde 100644 --- a/trunk/fs/lockd/svclock.c +++ b/trunk/fs/lockd/svclock.c @@ -795,7 +795,6 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) dprintk("lockd: GRANT_MSG RPC callback\n"); - lock_kernel(); /* if the block is not on a list at this point then it has * been invalidated. Don't try to requeue it. * @@ -805,7 +804,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) * for nlm_blocked? */ if (list_empty(&block->b_list)) - goto out; + return; /* Technically, we should down the file semaphore here. Since we * move the block towards the head of the queue only, no harm @@ -819,17 +818,13 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) } nlmsvc_insert_block(block, timeout); svc_wake_up(block->b_daemon); -out: - unlock_kernel(); } static void nlmsvc_grant_release(void *data) { struct nlm_rqst *call = data; - lock_kernel(); nlmsvc_release_block(call->a_block); - unlock_kernel(); } static const struct rpc_call_ops nlmsvc_grant_ops = { diff --git a/trunk/fs/lockd/svcproc.c b/trunk/fs/lockd/svcproc.c index ce6952b50a75..88379cc6e0b1 100644 --- a/trunk/fs/lockd/svcproc.c +++ b/trunk/fs/lockd/svcproc.c @@ -278,9 +278,7 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data) static void nlmsvc_callback_release(void *data) { - lock_kernel(); nlm_release_call(data); - unlock_kernel(); } static const struct rpc_call_ops nlmsvc_callback_ops = { diff --git a/trunk/fs/nfs/callback.c b/trunk/fs/nfs/callback.c index f447f4b4476c..c1e7c8300629 100644 --- a/trunk/fs/nfs/callback.c +++ b/trunk/fs/nfs/callback.c @@ -27,7 +27,7 @@ struct nfs_callback_data { unsigned int users; - struct svc_rqst *rqst; + struct svc_serv *serv; struct task_struct *task; }; @@ -91,17 +91,21 @@ nfs_callback_svc(void *vrqstp) svc_process(rqstp); } unlock_kernel(); + nfs_callback_info.task = NULL; + svc_exit_thread(rqstp); return 0; } /* - * Bring up the callback thread if it is not already up. + * Bring up the server process if it is not already up. */ int nfs_callback_up(void) { struct svc_serv *serv = NULL; + struct svc_rqst *rqstp; int ret = 0; + lock_kernel(); mutex_lock(&nfs_callback_mutex); if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) goto out; @@ -117,23 +121,22 @@ int nfs_callback_up(void) nfs_callback_tcpport = ret; dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); - nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); - if (IS_ERR(nfs_callback_info.rqst)) { - ret = PTR_ERR(nfs_callback_info.rqst); - nfs_callback_info.rqst = NULL; + rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); + if (IS_ERR(rqstp)) { + ret = PTR_ERR(rqstp); goto out_err; } svc_sock_update_bufs(serv); + nfs_callback_info.serv = serv; - nfs_callback_info.task = kthread_run(nfs_callback_svc, - nfs_callback_info.rqst, + nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp, "nfsv4-svc"); if (IS_ERR(nfs_callback_info.task)) { ret = PTR_ERR(nfs_callback_info.task); - svc_exit_thread(nfs_callback_info.rqst); - nfs_callback_info.rqst = NULL; + nfs_callback_info.serv = NULL; nfs_callback_info.task = NULL; + svc_exit_thread(rqstp); goto out_err; } out: @@ -146,6 +149,7 @@ int nfs_callback_up(void) if (serv) svc_destroy(serv); mutex_unlock(&nfs_callback_mutex); + unlock_kernel(); return ret; out_err: dprintk("Couldn't create callback socket or server thread; err = %d\n", @@ -155,19 +159,17 @@ int nfs_callback_up(void) } /* - * Kill the callback thread if it's no longer being used. + * Kill the server process if it is not already down. */ void nfs_callback_down(void) { + lock_kernel(); mutex_lock(&nfs_callback_mutex); nfs_callback_info.users--; - if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { + if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) kthread_stop(nfs_callback_info.task); - svc_exit_thread(nfs_callback_info.rqst); - nfs_callback_info.rqst = NULL; - nfs_callback_info.task = NULL; - } mutex_unlock(&nfs_callback_mutex); + unlock_kernel(); } static int nfs_callback_authenticate(struct svc_rqst *rqstp) diff --git a/trunk/fs/nfs/client.c b/trunk/fs/nfs/client.c index 5ee23e7058b3..f2a092ca69b5 100644 --- a/trunk/fs/nfs/client.c +++ b/trunk/fs/nfs/client.c @@ -431,14 +431,14 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, { to->to_initval = timeo * HZ / 10; to->to_retries = retrans; + if (!to->to_retries) + to->to_retries = 2; switch (proto) { case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_RDMA: - if (to->to_retries == 0) - to->to_retries = NFS_DEF_TCP_RETRANS; if (to->to_initval == 0) - to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10; + to->to_initval = 60 * HZ; if (to->to_initval > NFS_MAX_TCP_TIMEOUT) to->to_initval = NFS_MAX_TCP_TIMEOUT; to->to_increment = to->to_initval; @@ -450,17 +450,14 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, to->to_exponential = 0; break; case XPRT_TRANSPORT_UDP: - if (to->to_retries == 0) - to->to_retries = NFS_DEF_UDP_RETRANS; + default: if (!to->to_initval) - to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10; + to->to_initval = 11 * HZ / 10; if (to->to_initval > NFS_MAX_UDP_TIMEOUT) to->to_initval = NFS_MAX_UDP_TIMEOUT; to->to_maxval = NFS_MAX_UDP_TIMEOUT; to->to_exponential = 1; break; - default: - BUG(); } } diff --git a/trunk/fs/nfs/dir.c b/trunk/fs/nfs/dir.c index 28a238dab23a..982a2064fe4c 100644 --- a/trunk/fs/nfs/dir.c +++ b/trunk/fs/nfs/dir.c @@ -133,14 +133,13 @@ nfs_opendir(struct inode *inode, struct file *filp) { int res; - dfprintk(FILE, "NFS: open dir(%s/%s)\n", - filp->f_path.dentry->d_parent->d_name.name, - filp->f_path.dentry->d_name.name); - - nfs_inc_stats(inode, NFSIOS_VFSOPEN); + dfprintk(VFS, "NFS: opendir(%s/%ld)\n", + inode->i_sb->s_id, inode->i_ino); + lock_kernel(); /* Call generic open code in order to cache credentials */ res = nfs_open(inode, filp); + unlock_kernel(); return res; } @@ -529,11 +528,13 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) struct nfs_fattr fattr; long res; - dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", + dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n", dentry->d_parent->d_name.name, dentry->d_name.name, (long long)filp->f_pos); nfs_inc_stats(inode, NFSIOS_VFSGETDENTS); + lock_kernel(); + /* * filp->f_pos points to the dirent entry number. * *desc->dir_cookie has the cookie for the next entry. We have @@ -591,9 +592,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } out: nfs_unblock_sillyrename(dentry); + unlock_kernel(); if (res > 0) res = 0; - dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n", + dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n", dentry->d_parent->d_name.name, dentry->d_name.name, res); return res; @@ -601,15 +603,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) { - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; - - dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", - dentry->d_parent->d_name.name, - dentry->d_name.name, - offset, origin); - - mutex_lock(&inode->i_mutex); + mutex_lock(&filp->f_path.dentry->d_inode->i_mutex); switch (origin) { case 1: offset += filp->f_pos; @@ -625,7 +619,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) nfs_file_open_context(filp)->dir_cookie = 0; } out: - mutex_unlock(&inode->i_mutex); + mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex); return offset; } @@ -635,11 +629,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) */ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) { - dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", + dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, datasync); - nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); return 0; } @@ -774,6 +767,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) struct nfs_fattr fattr; parent = dget_parent(dentry); + lock_kernel(); dir = parent->d_inode; nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); inode = dentry->d_inode; @@ -811,6 +805,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_valid: + unlock_kernel(); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", __func__, dentry->d_parent->d_name.name, @@ -829,6 +824,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) shrink_dcache_parent(dentry); } d_drop(dentry); + unlock_kernel(); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", __func__, dentry->d_parent->d_name.name, @@ -862,14 +858,6 @@ static int nfs_dentry_delete(struct dentry *dentry) } -static void nfs_drop_nlink(struct inode *inode) -{ - spin_lock(&inode->i_lock); - if (inode->i_nlink > 0) - drop_nlink(inode); - spin_unlock(&inode->i_lock); -} - /* * Called when the dentry loses inode. * We use it to clean up silly-renamed files. @@ -881,8 +869,10 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + lock_kernel(); drop_nlink(inode); nfs_complete_unlink(dentry, inode); + unlock_kernel(); } iput(inode); } @@ -913,6 +903,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru res = ERR_PTR(-ENOMEM); dentry->d_op = NFS_PROTO(dir)->dentry_ops; + lock_kernel(); + /* * If we're doing an exclusive create, optimize away the lookup * but don't hash the dentry. @@ -920,7 +912,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru if (nfs_is_exclusive_create(dir, nd)) { d_instantiate(dentry, NULL); res = NULL; - goto out; + goto out_unlock; } parent = dentry->d_parent; @@ -948,6 +940,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_unblock_sillyrename: nfs_unblock_sillyrename(parent); +out_unlock: + unlock_kernel(); out: return res; } @@ -1005,7 +999,9 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry } /* Open the file on the server */ + lock_kernel(); res = nfs4_atomic_open(dir, dentry, nd); + unlock_kernel(); if (IS_ERR(res)) { error = PTR_ERR(res); switch (error) { @@ -1067,7 +1063,9 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) * operations that change the directory. We therefore save the * change attribute *before* we do the RPC call. */ + lock_kernel(); ret = nfs4_open_revalidate(dir, dentry, openflags, nd); + unlock_kernel(); out: dput(parent); if (!ret) @@ -1220,11 +1218,14 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, if ((nd->flags & LOOKUP_CREATE) != 0) open_flags = nd->intent.open.flags; + lock_kernel(); error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); if (error != 0) goto out_err; + unlock_kernel(); return 0; out_err: + unlock_kernel(); d_drop(dentry); return error; } @@ -1247,11 +1248,14 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; + lock_kernel(); status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); if (status != 0) goto out_err; + unlock_kernel(); return 0; out_err: + unlock_kernel(); d_drop(dentry); return status; } @@ -1270,12 +1274,15 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) attr.ia_valid = ATTR_MODE; attr.ia_mode = mode | S_IFDIR; + lock_kernel(); error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); if (error != 0) goto out_err; + unlock_kernel(); return 0; out_err: d_drop(dentry); + unlock_kernel(); return error; } @@ -1292,12 +1299,14 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); + lock_kernel(); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Ensure the VFS deletes this inode */ if (error == 0 && dentry->d_inode != NULL) clear_nlink(dentry->d_inode); else if (error == -ENOENT) nfs_dentry_handle_enoent(dentry); + unlock_kernel(); return error; } @@ -1399,7 +1408,7 @@ static int nfs_safe_remove(struct dentry *dentry) error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); /* The VFS may want to delete this inode */ if (error == 0) - nfs_drop_nlink(inode); + drop_nlink(inode); nfs_mark_for_revalidate(inode); } else error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); @@ -1422,6 +1431,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); + lock_kernel(); spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1) { @@ -1430,6 +1440,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) /* Start asynchronous writeout of the inode */ write_inode_now(dentry->d_inode, 0); error = nfs_sillyrename(dir, dentry); + unlock_kernel(); return error; } if (!d_unhashed(dentry)) { @@ -1443,6 +1454,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); } else if (need_rehash) d_rehash(dentry); + unlock_kernel(); return error; } @@ -1479,9 +1491,13 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym attr.ia_mode = S_IFLNK | S_IRWXUGO; attr.ia_valid = ATTR_MODE; + lock_kernel(); + page = alloc_page(GFP_HIGHUSER); - if (!page) + if (!page) { + unlock_kernel(); return -ENOMEM; + } kaddr = kmap_atomic(page, KM_USER0); memcpy(kaddr, symname, pathlen); @@ -1496,6 +1512,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym dentry->d_name.name, symname, error); d_drop(dentry); __free_page(page); + unlock_kernel(); return error; } @@ -1513,6 +1530,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym } else __free_page(page); + unlock_kernel(); return 0; } @@ -1526,12 +1544,14 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) old_dentry->d_parent->d_name.name, old_dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name); + lock_kernel(); d_drop(dentry); error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); if (error == 0) { atomic_inc(&inode->i_count); d_add(dentry, inode); } + unlock_kernel(); return error; } @@ -1571,6 +1591,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, * To prevent any new references to the target during the rename, * we unhash the dentry and free the inode in advance. */ + lock_kernel(); if (!d_unhashed(new_dentry)) { d_drop(new_dentry); rehash = new_dentry; @@ -1614,7 +1635,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* dentry still busy? */ goto out; } else - nfs_drop_nlink(new_inode); + drop_nlink(new_inode); go_ahead: /* @@ -1648,6 +1669,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* new dentry created? */ if (dentry) dput(dentry); + unlock_kernel(); return error; } @@ -1940,6 +1962,8 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) } force_lookup: + lock_kernel(); + if (!NFS_PROTO(inode)->access) goto out_notsup; @@ -1949,6 +1973,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) put_rpccred(cred); } else res = PTR_ERR(cred); + unlock_kernel(); out: dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", inode->i_sb->s_id, inode->i_ino, mask, res); @@ -1957,6 +1982,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) res = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (res == 0) res = generic_permission(inode, mask, NULL); + unlock_kernel(); goto out; } diff --git a/trunk/fs/nfs/direct.c b/trunk/fs/nfs/direct.c index 08f6b040d289..4757a2b326a1 100644 --- a/trunk/fs/nfs/direct.c +++ b/trunk/fs/nfs/direct.c @@ -890,7 +890,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, count = iov_length(iov, nr_segs); nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); - dfprintk(FILE, "NFS: direct read(%s/%s, %zd@%Ld)\n", + dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, count, (long long) pos); @@ -947,7 +947,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, count = iov_length(iov, nr_segs); nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); - dfprintk(FILE, "NFS: direct write(%s/%s, %zd@%Ld)\n", + dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, count, (long long) pos); diff --git a/trunk/fs/nfs/file.c b/trunk/fs/nfs/file.c index 78460657f5cb..4e98a56a1777 100644 --- a/trunk/fs/nfs/file.c +++ b/trunk/fs/nfs/file.c @@ -50,7 +50,7 @@ static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, unsigned long nr_segs, loff_t pos); static int nfs_file_flush(struct file *, fl_owner_t id); -static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync); +static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); static int nfs_check_flags(int flags); static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); @@ -72,7 +72,7 @@ const struct file_operations nfs_file_operations = { .open = nfs_file_open, .flush = nfs_file_flush, .release = nfs_file_release, - .fsync = nfs_file_fsync, + .fsync = nfs_fsync, .lock = nfs_lock, .flock = nfs_flock, .splice_read = nfs_file_splice_read, @@ -119,33 +119,25 @@ nfs_file_open(struct inode *inode, struct file *filp) { int res; - dprintk("NFS: open file(%s/%s)\n", - filp->f_path.dentry->d_parent->d_name.name, - filp->f_path.dentry->d_name.name); - res = nfs_check_flags(filp->f_flags); if (res) return res; nfs_inc_stats(inode, NFSIOS_VFSOPEN); - res = nfs_open(inode, filp); + lock_kernel(); + res = NFS_PROTO(inode)->file_open(inode, filp); + unlock_kernel(); return res; } static int nfs_file_release(struct inode *inode, struct file *filp) { - struct dentry *dentry = filp->f_path.dentry; - - dprintk("NFS: release(%s/%s)\n", - dentry->d_parent->d_name.name, - dentry->d_name.name); - /* Ensure that dirty pages are flushed out with the right creds */ if (filp->f_mode & FMODE_WRITE) - nfs_wb_all(dentry->d_inode); + nfs_wb_all(filp->f_path.dentry->d_inode); nfs_inc_stats(inode, NFSIOS_VFSRELEASE); - return nfs_release(inode, filp); + return NFS_PROTO(inode)->file_release(inode, filp); } /** @@ -179,12 +171,6 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) { loff_t loff; - - dprintk("NFS: llseek file(%s/%s, %lld, %d)\n", - filp->f_path.dentry->d_parent->d_name.name, - filp->f_path.dentry->d_name.name, - offset, origin); - /* origin == SEEK_END => we must revalidate the cached file length */ if (origin == SEEK_END) { struct inode *inode = filp->f_mapping->host; @@ -199,7 +185,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) } /* - * Helper for nfs_file_flush() and nfs_file_fsync() + * Helper for nfs_file_flush() and nfs_fsync() * * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to * disk, but it retrieves and clears ctx->error after synching, despite @@ -225,18 +211,16 @@ static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) /* * Flush all dirty pages, and check for write errors. + * */ static int nfs_file_flush(struct file *file, fl_owner_t id) { struct nfs_open_context *ctx = nfs_file_open_context(file); - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; int status; - dprintk("NFS: flush(%s/%s)\n", - dentry->d_parent->d_name.name, - dentry->d_name.name); + dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); if ((file->f_mode & FMODE_WRITE) == 0) return 0; @@ -261,7 +245,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, if (iocb->ki_filp->f_flags & O_DIRECT) return nfs_file_direct_read(iocb, iov, nr_segs, pos); - dprintk("NFS: read(%s/%s, %lu@%lu)\n", + dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long) pos); @@ -281,7 +265,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, struct inode *inode = dentry->d_inode; ssize_t res; - dprintk("NFS: splice_read(%s/%s, %lu@%Lu)\n", + dfprintk(VFS, "nfs: splice_read(%s/%s, %lu@%Lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long long) *ppos); @@ -298,7 +282,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) struct inode *inode = dentry->d_inode; int status; - dprintk("NFS: mmap(%s/%s)\n", + dfprintk(VFS, "nfs: mmap(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); status = nfs_revalidate_mapping(inode, file->f_mapping); @@ -316,14 +300,12 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) * whether any write errors occurred for this process. */ static int -nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) +nfs_fsync(struct file *file, struct dentry *dentry, int datasync) { struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = dentry->d_inode; - dprintk("NFS: fsync file(%s/%s) datasync %d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - datasync); + dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); nfs_inc_stats(inode, NFSIOS_VFSFSYNC); return nfs_do_fsync(ctx, inode); @@ -346,11 +328,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, struct page *page; index = pos >> PAGE_CACHE_SHIFT; - dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", - file->f_path.dentry->d_parent->d_name.name, - file->f_path.dentry->d_name.name, - mapping->host->i_ino, len, (long long) pos); - page = __grab_cache_page(mapping, index); if (!page) return -ENOMEM; @@ -371,32 +348,9 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, unsigned offset = pos & (PAGE_CACHE_SIZE - 1); int status; - dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n", - file->f_path.dentry->d_parent->d_name.name, - file->f_path.dentry->d_name.name, - mapping->host->i_ino, len, (long long) pos); - - /* - * Zero any uninitialised parts of the page, and then mark the page - * as up to date if it turns out that we're extending the file. - */ - if (!PageUptodate(page)) { - unsigned pglen = nfs_page_length(page); - unsigned end = offset + len; - - if (pglen == 0) { - zero_user_segments(page, 0, offset, - end, PAGE_CACHE_SIZE); - SetPageUptodate(page); - } else if (end >= pglen) { - zero_user_segment(page, end, PAGE_CACHE_SIZE); - if (offset == 0) - SetPageUptodate(page); - } else - zero_user_segment(page, pglen, PAGE_CACHE_SIZE); - } - + lock_kernel(); status = nfs_updatepage(file, page, offset, copied); + unlock_kernel(); unlock_page(page); page_cache_release(page); @@ -408,8 +362,6 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, static void nfs_invalidate_page(struct page *page, unsigned long offset) { - dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); - if (offset != 0) return; /* Cancel any unstarted writes on this page */ @@ -418,20 +370,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) static int nfs_release_page(struct page *page, gfp_t gfp) { - dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); - /* If PagePrivate() is set, then the page is not freeable */ return 0; } static int nfs_launder_page(struct page *page) { - struct inode *inode = page->mapping->host; - - dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", - inode->i_ino, (long long)page_offset(page)); - - return nfs_wb_page(inode, page); + return nfs_wb_page(page->mapping->host, page); } const struct address_space_operations nfs_file_aops = { @@ -451,19 +396,13 @@ const struct address_space_operations nfs_file_aops = { static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) { struct file *filp = vma->vm_file; - struct dentry *dentry = filp->f_path.dentry; unsigned pagelen; int ret = -EINVAL; struct address_space *mapping; - dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - filp->f_mapping->host->i_ino, - (long long)page_offset(page)); - lock_page(page); mapping = page->mapping; - if (mapping != dentry->d_inode->i_mapping) + if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) goto out_unlock; ret = 0; @@ -511,9 +450,9 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, if (iocb->ki_filp->f_flags & O_DIRECT) return nfs_file_direct_write(iocb, iov, nr_segs, pos); - dprintk("NFS: write(%s/%s, %lu@%Ld)\n", + dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, - (unsigned long) count, (long long) pos); + inode->i_ino, (unsigned long) count, (long long) pos); result = -EBUSY; if (IS_SWAPFILE(inode)) @@ -647,8 +586,7 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * This makes locking act as a cache coherency point. */ nfs_sync_mapping(filp->f_mapping); - if (!nfs_have_delegation(inode, FMODE_READ)) - nfs_zap_caches(inode); + nfs_zap_caches(inode); out: return status; } @@ -658,35 +596,23 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) */ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { - struct inode *inode = filp->f_mapping->host; - int ret = -ENOLCK; + struct inode * inode = filp->f_mapping->host; - dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n", - filp->f_path.dentry->d_parent->d_name.name, - filp->f_path.dentry->d_name.name, + dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", + inode->i_sb->s_id, inode->i_ino, fl->fl_type, fl->fl_flags, (long long)fl->fl_start, (long long)fl->fl_end); - nfs_inc_stats(inode, NFSIOS_VFSLOCK); /* No mandatory locks over NFS */ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) - goto out_err; - - if (NFS_PROTO(inode)->lock_check_bounds != NULL) { - ret = NFS_PROTO(inode)->lock_check_bounds(fl); - if (ret < 0) - goto out_err; - } + return -ENOLCK; if (IS_GETLK(cmd)) - ret = do_getlk(filp, cmd, fl); - else if (fl->fl_type == F_UNLCK) - ret = do_unlk(filp, cmd, fl); - else - ret = do_setlk(filp, cmd, fl); -out_err: - return ret; + return do_getlk(filp, cmd, fl); + if (fl->fl_type == F_UNLCK) + return do_unlk(filp, cmd, fl); + return do_setlk(filp, cmd, fl); } /* @@ -694,9 +620,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) */ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) { - dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n", - filp->f_path.dentry->d_parent->d_name.name, - filp->f_path.dentry->d_name.name, + dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n", + filp->f_path.dentry->d_inode->i_sb->s_id, + filp->f_path.dentry->d_inode->i_ino, fl->fl_type, fl->fl_flags); /* @@ -719,15 +645,12 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) return do_setlk(filp, cmd, fl); } -/* - * There is no protocol support for leases, so we have no way to implement - * them correctly in the face of opens by other clients. - */ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) { - dprintk("NFS: setlease(%s/%s, arg=%ld)\n", - file->f_path.dentry->d_parent->d_name.name, - file->f_path.dentry->d_name.name, arg); - + /* + * There is no protocol support for leases, so we have no way + * to implement them correctly in the face of opens by other + * clients. + */ return -EINVAL; } diff --git a/trunk/fs/nfs/inode.c b/trunk/fs/nfs/inode.c index df23f987da6b..596c5d8e86f4 100644 --- a/trunk/fs/nfs/inode.c +++ b/trunk/fs/nfs/inode.c @@ -57,6 +57,8 @@ static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; static void nfs_invalidate_inode(struct inode *); static int nfs_update_inode(struct inode *, struct nfs_fattr *); +static void nfs_zap_acl_cache(struct inode *); + static struct kmem_cache * nfs_inode_cachep; static inline unsigned long @@ -165,7 +167,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) } } -void nfs_zap_acl_cache(struct inode *inode) +static void nfs_zap_acl_cache(struct inode *inode) { void (*clear_acl_cache)(struct inode *); @@ -345,7 +347,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) goto out; } -#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE) +#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET) int nfs_setattr(struct dentry *dentry, struct iattr *attr) @@ -367,9 +369,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) /* Optimization: if the end result is no change, don't RPC */ attr->ia_valid &= NFS_VALID_ATTRS; - if ((attr->ia_valid & ~ATTR_FILE) == 0) + if (attr->ia_valid == 0) return 0; + lock_kernel(); /* Write all dirty data */ if (S_ISREG(inode->i_mode)) { filemap_write_and_wait(inode->i_mapping); @@ -383,65 +386,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); if (error == 0) nfs_refresh_inode(inode, &fattr); + unlock_kernel(); return error; } -/** - * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall - * @inode: inode of the file used - * @offset: file offset to start truncating - * - * This is a copy of the common vmtruncate, but with the locking - * corrected to take into account the fact that NFS requires - * inode->i_size to be updated under the inode->i_lock. - */ -static int nfs_vmtruncate(struct inode * inode, loff_t offset) -{ - if (i_size_read(inode) < offset) { - unsigned long limit; - - limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; - if (limit != RLIM_INFINITY && offset > limit) - goto out_sig; - if (offset > inode->i_sb->s_maxbytes) - goto out_big; - spin_lock(&inode->i_lock); - i_size_write(inode, offset); - spin_unlock(&inode->i_lock); - } else { - struct address_space *mapping = inode->i_mapping; - - /* - * truncation of in-use swapfiles is disallowed - it would - * cause subsequent swapout to scribble on the now-freed - * blocks. - */ - if (IS_SWAPFILE(inode)) - return -ETXTBSY; - spin_lock(&inode->i_lock); - i_size_write(inode, offset); - spin_unlock(&inode->i_lock); - - /* - * unmap_mapping_range is called twice, first simply for - * efficiency so that truncate_inode_pages does fewer - * single-page unmaps. However after this first call, and - * before truncate_inode_pages finishes, it is possible for - * private pages to be COWed, which remain after - * truncate_inode_pages finishes, hence the second - * unmap_mapping_range call must be made for correctness. - */ - unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); - truncate_inode_pages(mapping, offset); - unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); - } - return 0; -out_sig: - send_sig(SIGXFSZ, current, 0); -out_big: - return -EFBIG; -} - /** * nfs_setattr_update_inode - Update inode metadata after a setattr call. * @inode: pointer to struct inode @@ -468,7 +416,8 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) } if ((attr->ia_valid & ATTR_SIZE) != 0) { nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); - nfs_vmtruncate(inode, attr->ia_size); + inode->i_size = attr->ia_size; + vmtruncate(inode, attr->ia_size); } } @@ -698,6 +647,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) inode->i_sb->s_id, (long long)NFS_FILEID(inode)); nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); + lock_kernel(); if (is_bad_inode(inode)) goto out_nowait; if (NFS_STALE(inode)) @@ -746,6 +696,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) nfs_wake_up_inode(inode); out_nowait: + unlock_kernel(); return status; } @@ -880,9 +831,9 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) if (S_ISDIR(inode->i_mode)) nfsi->cache_validity |= NFS_INO_INVALID_DATA; } - if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) && + if (inode->i_size == nfs_size_to_loff_t(fattr->pre_size) && nfsi->npages == 0) - i_size_write(inode, nfs_size_to_loff_t(fattr->size)); + inode->i_size = nfs_size_to_loff_t(fattr->size); } } @@ -1023,7 +974,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa (fattr->valid & NFS_ATTR_WCC) == 0) { memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime)); memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime)); - fattr->pre_size = i_size_read(inode); + fattr->pre_size = inode->i_size; fattr->valid |= NFS_ATTR_WCC; } return nfs_post_op_update_inode(inode, fattr); @@ -1108,7 +1059,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) /* Do we perhaps have any outstanding writes, or has * the file grown beyond our last write? */ if (nfsi->npages == 0 || new_isize > cur_isize) { - i_size_write(inode, new_isize); + inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } dprintk("NFS: isize change on server for file %s/%ld\n", diff --git a/trunk/fs/nfs/internal.h b/trunk/fs/nfs/internal.h index 24241fcbb98d..04ae867dddba 100644 --- a/trunk/fs/nfs/internal.h +++ b/trunk/fs/nfs/internal.h @@ -150,7 +150,6 @@ extern void nfs_clear_inode(struct inode *); #ifdef CONFIG_NFS_V4 extern void nfs4_clear_inode(struct inode *); #endif -void nfs_zap_acl_cache(struct inode *inode); /* super.c */ extern struct file_system_type nfs_xdev_fs_type; diff --git a/trunk/fs/nfs/iostat.h b/trunk/fs/nfs/iostat.h index a36952810032..6350ecbde589 100644 --- a/trunk/fs/nfs/iostat.h +++ b/trunk/fs/nfs/iostat.h @@ -5,41 +5,135 @@ * * Copyright (C) 2005, 2006 Chuck Lever * + * NFS client per-mount statistics provide information about the health of + * the NFS client and the health of each NFS mount point. Generally these + * are not for detailed problem diagnosis, but simply to indicate that there + * is a problem. + * + * These counters are not meant to be human-readable, but are meant to be + * integrated into system monitoring tools such as "sar" and "iostat". As + * such, the counters are sampled by the tools over time, and are never + * zeroed after a file system is mounted. Moving averages can be computed + * by the tools by taking the difference between two instantaneous samples + * and dividing that by the time between the samples. */ #ifndef _NFS_IOSTAT #define _NFS_IOSTAT +#define NFS_IOSTAT_VERS "1.0" + +/* + * NFS byte counters + * + * 1. SERVER - the number of payload bytes read from or written to the + * server by the NFS client via an NFS READ or WRITE request. + * + * 2. NORMAL - the number of bytes read or written by applications via + * the read(2) and write(2) system call interfaces. + * + * 3. DIRECT - the number of bytes read or written from files opened + * with the O_DIRECT flag. + * + * These counters give a view of the data throughput into and out of the NFS + * client. Comparing the number of bytes requested by an application with the + * number of bytes the client requests from the server can provide an + * indication of client efficiency (per-op, cache hits, etc). + * + * These counters can also help characterize which access methods are in + * use. DIRECT by itself shows whether there is any O_DIRECT traffic. + * NORMAL + DIRECT shows how much data is going through the system call + * interface. A large amount of SERVER traffic without much NORMAL or + * DIRECT traffic shows that applications are using mapped files. + * + * NFS page counters + * + * These count the number of pages read or written via nfs_readpage(), + * nfs_readpages(), or their write equivalents. + */ +enum nfs_stat_bytecounters { + NFSIOS_NORMALREADBYTES = 0, + NFSIOS_NORMALWRITTENBYTES, + NFSIOS_DIRECTREADBYTES, + NFSIOS_DIRECTWRITTENBYTES, + NFSIOS_SERVERREADBYTES, + NFSIOS_SERVERWRITTENBYTES, + NFSIOS_READPAGES, + NFSIOS_WRITEPAGES, + __NFSIOS_BYTESMAX, +}; + +/* + * NFS event counters + * + * These counters provide a low-overhead way of monitoring client activity + * without enabling NFS trace debugging. The counters show the rate at + * which VFS requests are made, and how often the client invalidates its + * data and attribute caches. This allows system administrators to monitor + * such things as how close-to-open is working, and answer questions such + * as "why are there so many GETATTR requests on the wire?" + * + * They also count anamolous events such as short reads and writes, silly + * renames due to close-after-delete, and operations that change the size + * of a file (such operations can often be the source of data corruption + * if applications aren't using file locking properly). + */ +enum nfs_stat_eventcounters { + NFSIOS_INODEREVALIDATE = 0, + NFSIOS_DENTRYREVALIDATE, + NFSIOS_DATAINVALIDATE, + NFSIOS_ATTRINVALIDATE, + NFSIOS_VFSOPEN, + NFSIOS_VFSLOOKUP, + NFSIOS_VFSACCESS, + NFSIOS_VFSUPDATEPAGE, + NFSIOS_VFSREADPAGE, + NFSIOS_VFSREADPAGES, + NFSIOS_VFSWRITEPAGE, + NFSIOS_VFSWRITEPAGES, + NFSIOS_VFSGETDENTS, + NFSIOS_VFSSETATTR, + NFSIOS_VFSFLUSH, + NFSIOS_VFSFSYNC, + NFSIOS_VFSLOCK, + NFSIOS_VFSRELEASE, + NFSIOS_CONGESTIONWAIT, + NFSIOS_SETATTRTRUNC, + NFSIOS_EXTENDWRITE, + NFSIOS_SILLYRENAME, + NFSIOS_SHORTREAD, + NFSIOS_SHORTWRITE, + NFSIOS_DELAY, + __NFSIOS_COUNTSMAX, +}; + +#ifdef __KERNEL__ + #include #include -#include struct nfs_iostats { unsigned long long bytes[__NFSIOS_BYTESMAX]; unsigned long events[__NFSIOS_COUNTSMAX]; } ____cacheline_aligned; -static inline void nfs_inc_server_stats(const struct nfs_server *server, - enum nfs_stat_eventcounters stat) +static inline void nfs_inc_server_stats(struct nfs_server *server, enum nfs_stat_eventcounters stat) { struct nfs_iostats *iostats; int cpu; cpu = get_cpu(); iostats = per_cpu_ptr(server->io_stats, cpu); - iostats->events[stat]++; + iostats->events[stat] ++; put_cpu_no_resched(); } -static inline void nfs_inc_stats(const struct inode *inode, - enum nfs_stat_eventcounters stat) +static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat) { nfs_inc_server_stats(NFS_SERVER(inode), stat); } -static inline void nfs_add_server_stats(const struct nfs_server *server, - enum nfs_stat_bytecounters stat, - unsigned long addend) +static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat_bytecounters stat, unsigned long addend) { struct nfs_iostats *iostats; int cpu; @@ -50,9 +144,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server, put_cpu_no_resched(); } -static inline void nfs_add_stats(const struct inode *inode, - enum nfs_stat_bytecounters stat, - unsigned long addend) +static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend) { nfs_add_server_stats(NFS_SERVER(inode), stat, addend); } @@ -68,4 +160,5 @@ static inline void nfs_free_iostats(struct nfs_iostats *stats) free_percpu(stats); } -#endif /* _NFS_IOSTAT */ +#endif +#endif diff --git a/trunk/fs/nfs/nfs3acl.c b/trunk/fs/nfs/nfs3acl.c index 423842f51ac9..9b7362565c0c 100644 --- a/trunk/fs/nfs/nfs3acl.c +++ b/trunk/fs/nfs/nfs3acl.c @@ -5,8 +5,6 @@ #include #include -#include "internal.h" - #define NFSDBG_FACILITY NFSDBG_PROC ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -207,8 +205,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); - if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) - nfs_zap_acl_cache(inode); acl = nfs3_get_cached_acl(inode, type); if (acl != ERR_PTR(-EAGAIN)) return acl; @@ -323,8 +319,9 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, dprintk("NFS call setacl\n"); msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; status = rpc_call_sync(server->client_acl, &msg, 0); - nfs_access_zap_cache(inode); - nfs_zap_acl_cache(inode); + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; + spin_unlock(&inode->i_lock); dprintk("NFS reply setacl: %d\n", status); /* pages may have been allocated at the xdr layer. */ diff --git a/trunk/fs/nfs/nfs3proc.c b/trunk/fs/nfs/nfs3proc.c index 1e750e4574a9..c3523ad03ed1 100644 --- a/trunk/fs/nfs/nfs3proc.c +++ b/trunk/fs/nfs/nfs3proc.c @@ -129,8 +129,6 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, int status; dprintk("NFS call setattr\n"); - if (sattr->ia_valid & ATTR_FILE) - msg.rpc_cred = nfs_file_cred(sattr->ia_file); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status == 0) @@ -250,53 +248,6 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, return status; } -struct nfs3_createdata { - struct rpc_message msg; - union { - struct nfs3_createargs create; - struct nfs3_mkdirargs mkdir; - struct nfs3_symlinkargs symlink; - struct nfs3_mknodargs mknod; - } arg; - struct nfs3_diropres res; - struct nfs_fh fh; - struct nfs_fattr fattr; - struct nfs_fattr dir_attr; -}; - -static struct nfs3_createdata *nfs3_alloc_createdata(void) -{ - struct nfs3_createdata *data; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data != NULL) { - data->msg.rpc_argp = &data->arg; - data->msg.rpc_resp = &data->res; - data->res.fh = &data->fh; - data->res.fattr = &data->fattr; - data->res.dir_attr = &data->dir_attr; - nfs_fattr_init(data->res.fattr); - nfs_fattr_init(data->res.dir_attr); - } - return data; -} - -static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data) -{ - int status; - - status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); - nfs_post_op_update_inode(dir, data->res.dir_attr); - if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); - return status; -} - -static void nfs3_free_createdata(struct nfs3_createdata *data) -{ - kfree(data); -} - /* * Create a regular file. * For now, we don't implement O_EXCL. @@ -305,60 +256,70 @@ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) { - struct nfs3_createdata *data; + struct nfs_fh fhandle; + struct nfs_fattr fattr; + struct nfs_fattr dir_attr; + struct nfs3_createargs arg = { + .fh = NFS_FH(dir), + .name = dentry->d_name.name, + .len = dentry->d_name.len, + .sattr = sattr, + }; + struct nfs3_diropres res = { + .dir_attr = &dir_attr, + .fh = &fhandle, + .fattr = &fattr + }; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; mode_t mode = sattr->ia_mode; - int status = -ENOMEM; + int status; dprintk("NFS call create %s\n", dentry->d_name.name); - - data = nfs3_alloc_createdata(); - if (data == NULL) - goto out; - - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; - data->arg.create.fh = NFS_FH(dir); - data->arg.create.name = dentry->d_name.name; - data->arg.create.len = dentry->d_name.len; - data->arg.create.sattr = sattr; - - data->arg.create.createmode = NFS3_CREATE_UNCHECKED; + arg.createmode = NFS3_CREATE_UNCHECKED; if (flags & O_EXCL) { - data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE; - data->arg.create.verifier[0] = jiffies; - data->arg.create.verifier[1] = current->pid; + arg.createmode = NFS3_CREATE_EXCLUSIVE; + arg.verifier[0] = jiffies; + arg.verifier[1] = current->pid; } sattr->ia_mode &= ~current->fs->umask; - for (;;) { - status = nfs3_do_create(dir, dentry, data); +again: + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); - if (status != -ENOTSUPP) - break; - /* If the server doesn't support the exclusive creation - * semantics, try again with simple 'guarded' mode. */ - switch (data->arg.create.createmode) { + /* If the server doesn't support the exclusive creation semantics, + * try again with simple 'guarded' mode. */ + if (status == -ENOTSUPP) { + switch (arg.createmode) { case NFS3_CREATE_EXCLUSIVE: - data->arg.create.createmode = NFS3_CREATE_GUARDED; + arg.createmode = NFS3_CREATE_GUARDED; break; case NFS3_CREATE_GUARDED: - data->arg.create.createmode = NFS3_CREATE_UNCHECKED; + arg.createmode = NFS3_CREATE_UNCHECKED; break; case NFS3_CREATE_UNCHECKED: goto out; } - nfs_fattr_init(data->res.dir_attr); - nfs_fattr_init(data->res.fattr); + goto again; } + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); if (status != 0) goto out; /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ - if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { + if (arg.createmode == NFS3_CREATE_EXCLUSIVE) { dprintk("NFS call setattr (post-create)\n"); if (!(sattr->ia_valid & ATTR_ATIME_SET)) @@ -369,15 +330,14 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ - status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); - nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); + status = nfs3_proc_setattr(dentry, &fattr, sattr); + nfs_post_op_update_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); - if (status != 0) - goto out; } + if (status != 0) + goto out; status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); out: - nfs3_free_createdata(data); dprintk("NFS reply create: %d\n", status); return status; } @@ -492,28 +452,40 @@ static int nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, unsigned int len, struct iattr *sattr) { - struct nfs3_createdata *data; - int status = -ENOMEM; + struct nfs_fh fhandle; + struct nfs_fattr fattr, dir_attr; + struct nfs3_symlinkargs arg = { + .fromfh = NFS_FH(dir), + .fromname = dentry->d_name.name, + .fromlen = dentry->d_name.len, + .pages = &page, + .pathlen = len, + .sattr = sattr + }; + struct nfs3_diropres res = { + .dir_attr = &dir_attr, + .fh = &fhandle, + .fattr = &fattr + }; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + int status; if (len > NFS3_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %s\n", dentry->d_name.name); - data = nfs3_alloc_createdata(); - if (data == NULL) + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_post_op_update_inode(dir, &dir_attr); + if (status != 0) goto out; - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; - data->arg.symlink.fromfh = NFS_FH(dir); - data->arg.symlink.fromname = dentry->d_name.name; - data->arg.symlink.fromlen = dentry->d_name.len; - data->arg.symlink.pages = &page; - data->arg.symlink.pathlen = len; - data->arg.symlink.sattr = sattr; - - status = nfs3_do_create(dir, dentry, data); - - nfs3_free_createdata(data); + status = nfs_instantiate(dentry, &fhandle, &fattr); out: dprintk("NFS reply symlink: %d\n", status); return status; @@ -522,31 +494,42 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, static int nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { - struct nfs3_createdata *data; + struct nfs_fh fhandle; + struct nfs_fattr fattr, dir_attr; + struct nfs3_mkdirargs arg = { + .fh = NFS_FH(dir), + .name = dentry->d_name.name, + .len = dentry->d_name.len, + .sattr = sattr + }; + struct nfs3_diropres res = { + .dir_attr = &dir_attr, + .fh = &fhandle, + .fattr = &fattr + }; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int mode = sattr->ia_mode; - int status = -ENOMEM; + int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); sattr->ia_mode &= ~current->fs->umask; - data = nfs3_alloc_createdata(); - if (data == NULL) + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_post_op_update_inode(dir, &dir_attr); + if (status != 0) goto out; - - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; - data->arg.mkdir.fh = NFS_FH(dir); - data->arg.mkdir.name = dentry->d_name.name; - data->arg.mkdir.len = dentry->d_name.len; - data->arg.mkdir.sattr = sattr; - - status = nfs3_do_create(dir, dentry, data); + status = nfs_instantiate(dentry, &fhandle, &fattr); if (status != 0) goto out; - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); out: - nfs3_free_createdata(data); dprintk("NFS reply mkdir: %d\n", status); return status; } @@ -632,50 +615,52 @@ static int nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { - struct nfs3_createdata *data; + struct nfs_fh fh; + struct nfs_fattr fattr, dir_attr; + struct nfs3_mknodargs arg = { + .fh = NFS_FH(dir), + .name = dentry->d_name.name, + .len = dentry->d_name.len, + .sattr = sattr, + .rdev = rdev + }; + struct nfs3_diropres res = { + .dir_attr = &dir_attr, + .fh = &fh, + .fattr = &fattr + }; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD], + .rpc_argp = &arg, + .rpc_resp = &res, + }; mode_t mode = sattr->ia_mode; - int status = -ENOMEM; + int status; + + switch (sattr->ia_mode & S_IFMT) { + case S_IFBLK: arg.type = NF3BLK; break; + case S_IFCHR: arg.type = NF3CHR; break; + case S_IFIFO: arg.type = NF3FIFO; break; + case S_IFSOCK: arg.type = NF3SOCK; break; + default: return -EINVAL; + } dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, MAJOR(rdev), MINOR(rdev)); sattr->ia_mode &= ~current->fs->umask; - data = nfs3_alloc_createdata(); - if (data == NULL) - goto out; - - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; - data->arg.mknod.fh = NFS_FH(dir); - data->arg.mknod.name = dentry->d_name.name; - data->arg.mknod.len = dentry->d_name.len; - data->arg.mknod.sattr = sattr; - data->arg.mknod.rdev = rdev; - - switch (sattr->ia_mode & S_IFMT) { - case S_IFBLK: - data->arg.mknod.type = NF3BLK; - break; - case S_IFCHR: - data->arg.mknod.type = NF3CHR; - break; - case S_IFIFO: - data->arg.mknod.type = NF3FIFO; - break; - case S_IFSOCK: - data->arg.mknod.type = NF3SOCK; - break; - default: - status = -EINVAL; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_post_op_update_inode(dir, &dir_attr); + if (status != 0) goto out; - } - - status = nfs3_do_create(dir, dentry, data); + status = nfs_instantiate(dentry, &fh, &fattr); if (status != 0) goto out; status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); out: - nfs3_free_createdata(data); dprintk("NFS reply mknod: %d\n", status); return status; } @@ -816,6 +801,8 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .write_done = nfs3_write_done, .commit_setup = nfs3_proc_commit_setup, .commit_done = nfs3_commit_done, + .file_open = nfs_open, + .file_release = nfs_release, .lock = nfs3_proc_lock, .clear_acl_cache = nfs3_forget_cached_acls, }; diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index c910413eaeca..1293e0acd82b 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -451,7 +451,9 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) /* Save the delegation */ memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); rcu_read_unlock(); + lock_kernel(); ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); + unlock_kernel(); if (ret != 0) goto out; ret = -EAGAIN; @@ -1137,9 +1139,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int return res; } -static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, - struct nfs_fattr *fattr, struct iattr *sattr, - struct nfs4_state *state) +static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, + struct iattr *sattr, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_setattrargs arg = { @@ -1153,10 +1154,9 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, .server = server, }; struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], - .rpc_argp = &arg, - .rpc_resp = &res, - .rpc_cred = cred, + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], + .rpc_argp = &arg, + .rpc_resp = &res, }; unsigned long timestamp = jiffies; int status; @@ -1166,6 +1166,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { /* Use that stateid */ } else if (state != NULL) { + msg.rpc_cred = state->owner->so_cred; nfs4_copy_stateid(&arg.stateid, state, current->files); } else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); @@ -1176,16 +1177,15 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, return status; } -static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, - struct nfs_fattr *fattr, struct iattr *sattr, - struct nfs4_state *state) +static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, + struct iattr *sattr, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(inode); struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(server, - _nfs4_do_setattr(inode, cred, fattr, sattr, state), + _nfs4_do_setattr(inode, fattr, sattr, state), &exception); } while (exception.retry); return err; @@ -1647,25 +1647,29 @@ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) { + struct rpc_cred *cred; struct inode *inode = dentry->d_inode; - struct rpc_cred *cred = NULL; + struct nfs_open_context *ctx; struct nfs4_state *state = NULL; int status; nfs_fattr_init(fattr); - /* Search for an existing open(O_WRITE) file */ - if (sattr->ia_valid & ATTR_FILE) { - struct nfs_open_context *ctx; + cred = rpc_lookup_cred(); + if (IS_ERR(cred)) + return PTR_ERR(cred); - ctx = nfs_file_open_context(sattr->ia_file); - cred = ctx->cred; + /* Search for an existing open(O_WRITE) file */ + ctx = nfs_find_open_context(inode, cred, FMODE_WRITE); + if (ctx != NULL) state = ctx->state; - } - status = nfs4_do_setattr(inode, cred, fattr, sattr, state); + status = nfs4_do_setattr(inode, fattr, sattr, state); if (status == 0) nfs_setattr_update_inode(inode, sattr); + if (ctx != NULL) + put_nfs_open_context(ctx); + put_rpccred(cred); return status; } @@ -1893,16 +1897,17 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, goto out; } state = nfs4_do_open(dir, &path, flags, sattr, cred); + put_rpccred(cred); d_drop(dentry); if (IS_ERR(state)) { status = PTR_ERR(state); - goto out_putcred; + goto out; } d_add(dentry, igrab(state->inode)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); if (flags & O_EXCL) { struct nfs_fattr fattr; - status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state); + status = nfs4_do_setattr(state->inode, &fattr, sattr, state); if (status == 0) nfs_setattr_update_inode(state->inode, sattr); nfs_post_op_update_inode(state->inode, &fattr); @@ -1911,8 +1916,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, status = nfs4_intent_set_file(nd, &path, state); else nfs4_close_sync(&path, state, flags); -out_putcred: - put_rpccred(cred); out: return status; } @@ -2076,81 +2079,47 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n return err; } -struct nfs4_createdata { - struct rpc_message msg; - struct nfs4_create_arg arg; - struct nfs4_create_res res; - struct nfs_fh fh; - struct nfs_fattr fattr; - struct nfs_fattr dir_fattr; -}; - -static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, - struct qstr *name, struct iattr *sattr, u32 ftype) -{ - struct nfs4_createdata *data; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data != NULL) { - struct nfs_server *server = NFS_SERVER(dir); - - data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE]; - data->msg.rpc_argp = &data->arg; - data->msg.rpc_resp = &data->res; - data->arg.dir_fh = NFS_FH(dir); - data->arg.server = server; - data->arg.name = name; - data->arg.attrs = sattr; - data->arg.ftype = ftype; - data->arg.bitmask = server->attr_bitmask; - data->res.server = server; - data->res.fh = &data->fh; - data->res.fattr = &data->fattr; - data->res.dir_fattr = &data->dir_fattr; - nfs_fattr_init(data->res.fattr); - nfs_fattr_init(data->res.dir_fattr); - } - return data; -} - -static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) -{ - int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); - if (status == 0) { - update_changeattr(dir, &data->res.dir_cinfo); - nfs_post_op_update_inode(dir, data->res.dir_fattr); - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); - } - return status; -} - -static void nfs4_free_createdata(struct nfs4_createdata *data) -{ - kfree(data); -} - static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, unsigned int len, struct iattr *sattr) { - struct nfs4_createdata *data; - int status = -ENAMETOOLONG; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fh fhandle; + struct nfs_fattr fattr, dir_fattr; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = &dentry->d_name, + .attrs = sattr, + .ftype = NF4LNK, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = &fhandle, + .fattr = &fattr, + .dir_fattr = &dir_fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + int status; if (len > NFS4_MAXPATHLEN) - goto out; + return -ENAMETOOLONG; - status = -ENOMEM; - data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK); - if (data == NULL) - goto out; - - data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK]; - data->arg.u.symlink.pages = &page; - data->arg.u.symlink.len = len; + arg.u.symlink.pages = &page; + arg.u.symlink.len = len; + nfs_fattr_init(&fattr); + nfs_fattr_init(&dir_fattr); - status = nfs4_do_create(dir, dentry, data); - - nfs4_free_createdata(data); -out: + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) { + update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr); + } return status; } @@ -2171,17 +2140,39 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { - struct nfs4_createdata *data; - int status = -ENOMEM; - - data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR); - if (data == NULL) - goto out; - - status = nfs4_do_create(dir, dentry, data); + struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fh fhandle; + struct nfs_fattr fattr, dir_fattr; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = &dentry->d_name, + .attrs = sattr, + .ftype = NF4DIR, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = &fhandle, + .fattr = &fattr, + .dir_fattr = &dir_fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + int status; - nfs4_free_createdata(data); -out: + nfs_fattr_init(&fattr); + nfs_fattr_init(&dir_fattr); + + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) { + update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr); + } return status; } @@ -2251,34 +2242,56 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { - struct nfs4_createdata *data; - int mode = sattr->ia_mode; - int status = -ENOMEM; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fh fh; + struct nfs_fattr fattr, dir_fattr; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = &dentry->d_name, + .attrs = sattr, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = &fh, + .fattr = &fattr, + .dir_fattr = &dir_fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + int status; + int mode = sattr->ia_mode; + + nfs_fattr_init(&fattr); + nfs_fattr_init(&dir_fattr); BUG_ON(!(sattr->ia_valid & ATTR_MODE)); BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); - - data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK); - if (data == NULL) - goto out; - if (S_ISFIFO(mode)) - data->arg.ftype = NF4FIFO; + arg.ftype = NF4FIFO; else if (S_ISBLK(mode)) { - data->arg.ftype = NF4BLK; - data->arg.u.device.specdata1 = MAJOR(rdev); - data->arg.u.device.specdata2 = MINOR(rdev); + arg.ftype = NF4BLK; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); } else if (S_ISCHR(mode)) { - data->arg.ftype = NF4CHR; - data->arg.u.device.specdata1 = MAJOR(rdev); - data->arg.u.device.specdata2 = MINOR(rdev); + arg.ftype = NF4CHR; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); } + else + arg.ftype = NF4SOCK; - status = nfs4_do_create(dir, dentry, data); - - nfs4_free_createdata(data); -out: + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (status == 0) { + update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); + status = nfs_instantiate(dentry, &fh, &fattr); + } return status; } @@ -2693,8 +2706,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) ret = nfs_revalidate_inode(server, inode); if (ret < 0) return ret; - if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) - nfs_zap_acl_cache(inode); ret = nfs4_read_cached_acl(inode, buf, buflen); if (ret != -ENOENT) return ret; @@ -2722,8 +2733,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl nfs_inode_return_delegation(inode); buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); - nfs_access_zap_cache(inode); - nfs_zap_acl_cache(inode); + nfs_zap_caches(inode); return ret; } @@ -2757,7 +2767,8 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) task->tk_status = 0; return -EAGAIN; case -NFS4ERR_DELAY: - nfs_inc_server_stats(server, NFSIOS_DELAY); + nfs_inc_server_stats((struct nfs_server *) server, + NFSIOS_DELAY); case -NFS4ERR_GRACE: rpc_delay(task, NFS4_POLL_RETRY_MAX); task->tk_status = 0; @@ -2922,7 +2933,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) { - long timeout = 0; + long timeout; int err; do { err = _nfs4_proc_setclientid_confirm(clp, cred); @@ -3714,6 +3725,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .write_done = nfs4_write_done, .commit_setup = nfs4_proc_commit_setup, .commit_done = nfs4_commit_done, + .file_open = nfs_open, + .file_release = nfs_release, .lock = nfs4_proc_lock, .clear_acl_cache = nfs4_zap_acl_attr, }; diff --git a/trunk/fs/nfs/nfs4state.c b/trunk/fs/nfs/nfs4state.c index 401ef8b28f97..856a8934f610 100644 --- a/trunk/fs/nfs/nfs4state.c +++ b/trunk/fs/nfs/nfs4state.c @@ -940,6 +940,7 @@ static int reclaimer(void *ptr) allow_signal(SIGKILL); /* Ensure exclusive access to NFSv4 state */ + lock_kernel(); down_write(&clp->cl_sem); /* Are there any NFS mounts out there? */ if (list_empty(&clp->cl_superblocks)) @@ -999,6 +1000,7 @@ static int reclaimer(void *ptr) nfs_delegation_reap_unclaimed(clp); out: up_write(&clp->cl_sem); + unlock_kernel(); if (status == -NFS4ERR_CB_PATH_DOWN) nfs_handle_cb_pathdown(clp); nfs4_clear_recover_bit(clp); diff --git a/trunk/fs/nfs/nfsroot.c b/trunk/fs/nfs/nfsroot.c index 46763d1cd397..531379d36823 100644 --- a/trunk/fs/nfs/nfsroot.c +++ b/trunk/fs/nfs/nfsroot.c @@ -1,4 +1,6 @@ /* + * $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $ + * * Copyright (C) 1995, 1996 Gero Kuhlmann * * Allow an NFS filesystem to be mounted as root. The way this works is: @@ -295,10 +297,10 @@ static int __init root_nfs_name(char *name) nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ nfs_data.rsize = NFS_DEF_FILE_IO_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_SIZE; - nfs_data.acregmin = NFS_DEF_ACREGMIN; - nfs_data.acregmax = NFS_DEF_ACREGMAX; - nfs_data.acdirmin = NFS_DEF_ACDIRMIN; - nfs_data.acdirmax = NFS_DEF_ACDIRMAX; + nfs_data.acregmin = 3; + nfs_data.acregmax = 60; + nfs_data.acdirmin = 30; + nfs_data.acdirmax = 60; strcpy(buf, NFS_ROOT); /* Process options received from the remote server */ diff --git a/trunk/fs/nfs/proc.c b/trunk/fs/nfs/proc.c index 4dbb84df1b68..03599bfe81cf 100644 --- a/trunk/fs/nfs/proc.c +++ b/trunk/fs/nfs/proc.c @@ -129,8 +129,6 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, sattr->ia_mode &= S_IALLUGO; dprintk("NFS call setattr\n"); - if (sattr->ia_valid & ATTR_FILE) - msg.rpc_cred = nfs_file_cred(sattr->ia_file); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status == 0) @@ -600,29 +598,6 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); } -/* Helper functions for NFS lock bounds checking */ -#define NFS_LOCK32_OFFSET_MAX ((__s32)0x7fffffffUL) -static int nfs_lock_check_bounds(const struct file_lock *fl) -{ - __s32 start, end; - - start = (__s32)fl->fl_start; - if ((loff_t)start != fl->fl_start) - goto out_einval; - - if (fl->fl_end != OFFSET_MAX) { - end = (__s32)fl->fl_end; - if ((loff_t)end != fl->fl_end) - goto out_einval; - } else - end = NFS_LOCK32_OFFSET_MAX; - - if (start < 0 || start > end) - goto out_einval; - return 0; -out_einval: - return -EINVAL; -} const struct nfs_rpc_ops nfs_v2_clientops = { .version = 2, /* protocol version */ @@ -655,6 +630,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .write_setup = nfs_proc_write_setup, .write_done = nfs_write_done, .commit_setup = nfs_proc_commit_setup, + .file_open = nfs_open, + .file_release = nfs_release, .lock = nfs_proc_lock, - .lock_check_bounds = nfs_lock_check_bounds, }; diff --git a/trunk/fs/nfs/super.c b/trunk/fs/nfs/super.c index 1b94e3650f5c..614efeed5437 100644 --- a/trunk/fs/nfs/super.c +++ b/trunk/fs/nfs/super.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -66,6 +65,7 @@ enum { /* Mount options that take no arguments */ Opt_soft, Opt_hard, + Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, @@ -92,8 +92,8 @@ enum { Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, Opt_addr, Opt_mountaddr, Opt_clientaddr, - /* Special mount options */ - Opt_userspace, Opt_deprecated, Opt_sloppy, + /* Mount options that are ignored */ + Opt_userspace, Opt_deprecated, Opt_err }; @@ -101,14 +101,10 @@ enum { static match_table_t nfs_mount_option_tokens = { { Opt_userspace, "bg" }, { Opt_userspace, "fg" }, - { Opt_userspace, "retry=%s" }, - - { Opt_sloppy, "sloppy" }, - { Opt_soft, "soft" }, { Opt_hard, "hard" }, - { Opt_deprecated, "intr" }, - { Opt_deprecated, "nointr" }, + { Opt_intr, "intr" }, + { Opt_nointr, "nointr" }, { Opt_posix, "posix" }, { Opt_noposix, "noposix" }, { Opt_cto, "cto" }, @@ -140,6 +136,7 @@ static match_table_t nfs_mount_option_tokens = { { Opt_acdirmin, "acdirmin=%u" }, { Opt_acdirmax, "acdirmax=%u" }, { Opt_actimeo, "actimeo=%u" }, + { Opt_userspace, "retry=%u" }, { Opt_namelen, "namlen=%u" }, { Opt_mountport, "mountport=%u" }, { Opt_mountvers, "mountvers=%u" }, @@ -210,7 +207,6 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); static void nfs_kill_super(struct super_block *); static void nfs_put_super(struct super_block *); -static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); static struct file_system_type nfs_fs_type = { .owner = THIS_MODULE, @@ -238,7 +234,6 @@ static const struct super_operations nfs_sops = { .umount_begin = nfs_umount_begin, .show_options = nfs_show_options, .show_stats = nfs_show_stats, - .remount_fs = nfs_remount, }; #ifdef CONFIG_NFS_V4 @@ -283,7 +278,6 @@ static const struct super_operations nfs4_sops = { .umount_begin = nfs_umount_begin, .show_options = nfs_show_options, .show_stats = nfs_show_stats, - .remount_fs = nfs_remount, }; #endif @@ -374,6 +368,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) }; int error; + lock_kernel(); + error = server->nfs_client->rpc_ops->statfs(server, fh, &res); if (error < 0) goto out_err; @@ -405,10 +401,12 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_namelen = server->namelen; + unlock_kernel(); return 0; out_err: dprintk("%s: statfs error = %d\n", __func__, -error); + unlock_kernel(); return error; } @@ -516,13 +514,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, if (nfss->bsize != 0) seq_printf(m, ",bsize=%u", nfss->bsize); seq_printf(m, ",namlen=%u", nfss->namelen); - if (nfss->acregmin != NFS_DEF_ACREGMIN*HZ || showdefaults) + if (nfss->acregmin != 3*HZ || showdefaults) seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); - if (nfss->acregmax != NFS_DEF_ACREGMAX*HZ || showdefaults) + if (nfss->acregmax != 60*HZ || showdefaults) seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); - if (nfss->acdirmin != NFS_DEF_ACDIRMIN*HZ || showdefaults) + if (nfss->acdirmin != 30*HZ || showdefaults) seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); - if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults) + if (nfss->acdirmax != 60*HZ || showdefaults) seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { if (nfss->flags & nfs_infop->flag) @@ -704,233 +702,49 @@ static int nfs_verify_server_address(struct sockaddr *addr) return 0; } -static void nfs_parse_ipv4_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - struct sockaddr_in *sin = (struct sockaddr_in *)sap; - u8 *addr = (u8 *)&sin->sin_addr.s_addr; - - if (str_len <= INET_ADDRSTRLEN) { - dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", - (int)str_len, string); - - sin->sin_family = AF_INET; - *addr_len = sizeof(*sin); - if (in4_pton(string, str_len, addr, '\0', NULL)) - return; - } - - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} - -#define IPV6_SCOPE_DELIMITER '%' - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, - const char *delim, - struct sockaddr_in6 *sin6) -{ - char *p; - size_t len; - - if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) - return ; - if (*delim != IPV6_SCOPE_DELIMITER) - return; - - len = (string + str_len) - delim - 1; - p = kstrndup(delim + 1, len, GFP_KERNEL); - if (p) { - unsigned long scope_id = 0; - struct net_device *dev; - - dev = dev_get_by_name(&init_net, p); - if (dev != NULL) { - scope_id = dev->ifindex; - dev_put(dev); - } else { - /* scope_id is set to zero on error */ - strict_strtoul(p, 10, &scope_id); - } - - kfree(p); - sin6->sin6_scope_id = scope_id; - dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); - } -} - -static void nfs_parse_ipv6_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; - const char *delim; - - if (str_len <= INET6_ADDRSTRLEN) { - dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", - (int)str_len, string); - - sin6->sin6_family = AF_INET6; - *addr_len = sizeof(*sin6); - if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { - nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); - return; - } - } - - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} -#else -static void nfs_parse_ipv6_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} -#endif - -/* - * Construct a sockaddr based on the contents of a string that contains - * an IP address in presentation format. - * - * If there is a problem constructing the new sockaddr, set the address - * family to AF_UNSPEC. - */ -static void nfs_parse_ip_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - unsigned int i, colons; - - colons = 0; - for (i = 0; i < str_len; i++) - if (string[i] == ':') - colons++; - - if (colons >= 2) - nfs_parse_ipv6_address(string, str_len, sap, addr_len); - else - nfs_parse_ipv4_address(string, str_len, sap, addr_len); -} - /* - * Sanity check the NFS transport protocol. + * Parse string addresses passed in via a mount option, + * and construct a sockaddr based on the result. * + * If address parsing fails, set the sockaddr's address + * family to AF_UNSPEC to force nfs_verify_server_address() + * to punt the mount. */ -static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt) -{ - switch (mnt->nfs_server.protocol) { - case XPRT_TRANSPORT_UDP: - case XPRT_TRANSPORT_TCP: - case XPRT_TRANSPORT_RDMA: - break; - default: - mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; - } -} - -/* - * For text based NFSv2/v3 mounts, the mount protocol transport default - * settings should depend upon the specified NFS transport. - */ -static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) +static void nfs_parse_server_address(char *value, + struct sockaddr *sap, + size_t *len) { - nfs_validate_transport_protocol(mnt); + if (strchr(value, ':')) { + struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; + u8 *addr = (u8 *)&ap->sin6_addr.in6_u; - if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP || - mnt->mount_server.protocol == XPRT_TRANSPORT_TCP) + ap->sin6_family = AF_INET6; + *len = sizeof(*ap); + if (in6_pton(value, -1, addr, '\0', NULL)) return; - switch (mnt->nfs_server.protocol) { - case XPRT_TRANSPORT_UDP: - mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; - break; - case XPRT_TRANSPORT_TCP: - case XPRT_TRANSPORT_RDMA: - mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; - } -} - -/* - * Parse the value of the 'sec=' option. - * - * The flavor_len setting is for v4 mounts. - */ -static int nfs_parse_security_flavors(char *value, - struct nfs_parsed_mount_data *mnt) -{ - substring_t args[MAX_OPT_ARGS]; - - dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); + } else { + struct sockaddr_in *ap = (struct sockaddr_in *)sap; + u8 *addr = (u8 *)&ap->sin_addr.s_addr; - switch (match_token(value, nfs_secflavor_tokens, args)) { - case Opt_sec_none: - mnt->auth_flavor_len = 0; - mnt->auth_flavors[0] = RPC_AUTH_NULL; - break; - case Opt_sec_sys: - mnt->auth_flavor_len = 0; - mnt->auth_flavors[0] = RPC_AUTH_UNIX; - break; - case Opt_sec_krb5: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; - break; - case Opt_sec_krb5i: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; - break; - case Opt_sec_krb5p: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; - break; - case Opt_sec_lkey: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; - break; - case Opt_sec_lkeyi: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; - break; - case Opt_sec_lkeyp: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; - break; - case Opt_sec_spkm: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; - break; - case Opt_sec_spkmi: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; - break; - case Opt_sec_spkmp: - mnt->auth_flavor_len = 1; - mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; - break; - default: - return 0; + ap->sin_family = AF_INET; + *len = sizeof(*ap); + if (in4_pton(value, -1, addr, '\0', NULL)) + return; } - return 1; -} - -static void nfs_parse_invalid_value(const char *option) -{ - dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); + sap->sa_family = AF_UNSPEC; + *len = 0; } /* * Error-check and convert a string of mount options from user space into - * a data structure. The whole mount string is processed; bad options are - * skipped as they are encountered. If there were no errors, return 1; - * otherwise return 0 (zero). + * a data structure */ static int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt) { char *p, *string, *secdata; - int rc, sloppy = 0, errors = 0; + int rc; if (!raw) { dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); @@ -963,16 +777,15 @@ static int nfs_parse_mount_options(char *raw, token = match_token(p, nfs_mount_option_tokens, args); switch (token) { - - /* - * boolean options: foo/nofoo - */ case Opt_soft: mnt->flags |= NFS_MOUNT_SOFT; break; case Opt_hard: mnt->flags &= ~NFS_MOUNT_SOFT; break; + case Opt_intr: + case Opt_nointr: + break; case Opt_posix: mnt->flags |= NFS_MOUNT_POSIX; break; @@ -1006,14 +819,20 @@ static int nfs_parse_mount_options(char *raw, case Opt_udp: mnt->flags &= ~NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; + mnt->timeo = 7; + mnt->retrans = 5; break; case Opt_tcp: mnt->flags |= NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; + mnt->timeo = 600; + mnt->retrans = 2; break; case Opt_rdma: mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; + mnt->timeo = 600; + mnt->retrans = 2; break; case Opt_acl: mnt->flags &= ~NFS_MOUNT_NOACL; @@ -1034,144 +853,165 @@ static int nfs_parse_mount_options(char *raw, mnt->flags |= NFS_MOUNT_UNSHARED; break; - /* - * options that take numeric values - */ case Opt_port: - if (match_int(args, &option) || - option < 0 || option > USHORT_MAX) { - errors++; - nfs_parse_invalid_value("port"); - } else - mnt->nfs_server.port = option; + if (match_int(args, &option)) + return 0; + if (option < 0 || option > 65535) + return 0; + mnt->nfs_server.port = option; break; case Opt_rsize: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("rsize"); - } else - mnt->rsize = option; + if (match_int(args, &mnt->rsize)) + return 0; break; case Opt_wsize: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("wsize"); - } else - mnt->wsize = option; + if (match_int(args, &mnt->wsize)) + return 0; break; case Opt_bsize: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("bsize"); - } else - mnt->bsize = option; + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->bsize = option; break; case Opt_timeo: - if (match_int(args, &option) || option <= 0) { - errors++; - nfs_parse_invalid_value("timeo"); - } else - mnt->timeo = option; + if (match_int(args, &mnt->timeo)) + return 0; break; case Opt_retrans: - if (match_int(args, &option) || option <= 0) { - errors++; - nfs_parse_invalid_value("retrans"); - } else - mnt->retrans = option; + if (match_int(args, &mnt->retrans)) + return 0; break; case Opt_acregmin: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("acregmin"); - } else - mnt->acregmin = option; + if (match_int(args, &mnt->acregmin)) + return 0; break; case Opt_acregmax: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("acregmax"); - } else - mnt->acregmax = option; + if (match_int(args, &mnt->acregmax)) + return 0; break; case Opt_acdirmin: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("acdirmin"); - } else - mnt->acdirmin = option; + if (match_int(args, &mnt->acdirmin)) + return 0; break; case Opt_acdirmax: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("acdirmax"); - } else - mnt->acdirmax = option; + if (match_int(args, &mnt->acdirmax)) + return 0; break; case Opt_actimeo: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("actimeo"); - } else - mnt->acregmin = mnt->acregmax = - mnt->acdirmin = mnt->acdirmax = option; + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->acregmin = + mnt->acregmax = + mnt->acdirmin = + mnt->acdirmax = option; break; case Opt_namelen: - if (match_int(args, &option) || option < 0) { - errors++; - nfs_parse_invalid_value("namlen"); - } else - mnt->namlen = option; + if (match_int(args, &mnt->namlen)) + return 0; break; case Opt_mountport: - if (match_int(args, &option) || - option < 0 || option > USHORT_MAX) { - errors++; - nfs_parse_invalid_value("mountport"); - } else - mnt->mount_server.port = option; + if (match_int(args, &option)) + return 0; + if (option < 0 || option > 65535) + return 0; + mnt->mount_server.port = option; break; case Opt_mountvers: - if (match_int(args, &option) || - option < NFS_MNT_VERSION || - option > NFS_MNT3_VERSION) { - errors++; - nfs_parse_invalid_value("mountvers"); - } else - mnt->mount_server.version = option; + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->mount_server.version = option; break; case Opt_nfsvers: - if (match_int(args, &option)) { - errors++; - nfs_parse_invalid_value("nfsvers"); - break; - } + if (match_int(args, &option)) + return 0; switch (option) { - case NFS2_VERSION: + case 2: mnt->flags &= ~NFS_MOUNT_VER3; break; - case NFS3_VERSION: + case 3: mnt->flags |= NFS_MOUNT_VER3; break; default: - errors++; - nfs_parse_invalid_value("nfsvers"); + goto out_unrec_vers; } break; - /* - * options that take text values - */ case Opt_sec: string = match_strdup(args); if (string == NULL) goto out_nomem; - rc = nfs_parse_security_flavors(string, mnt); + token = match_token(string, nfs_secflavor_tokens, args); kfree(string); - if (!rc) { - errors++; - dfprintk(MOUNT, "NFS: unrecognized " - "security flavor\n"); + + /* + * The flags setting is for v2/v3. The flavor_len + * setting is for v4. v2/v3 also need to know the + * difference between NULL and UNIX. + */ + switch (token) { + case Opt_sec_none: + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 0; + mnt->auth_flavors[0] = RPC_AUTH_NULL; + break; + case Opt_sec_sys: + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 0; + mnt->auth_flavors[0] = RPC_AUTH_UNIX; + break; + case Opt_sec_krb5: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; + break; + case Opt_sec_krb5i: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; + break; + case Opt_sec_krb5p: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; + break; + case Opt_sec_lkey: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; + break; + case Opt_sec_lkeyi: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; + break; + case Opt_sec_lkeyp: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; + break; + case Opt_sec_spkm: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; + break; + case Opt_sec_spkmi: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; + break; + case Opt_sec_spkmp: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; + break; + default: + goto out_unrec_sec; } break; case Opt_proto: @@ -1186,20 +1026,24 @@ static int nfs_parse_mount_options(char *raw, case Opt_xprt_udp: mnt->flags &= ~NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; + mnt->timeo = 7; + mnt->retrans = 5; break; case Opt_xprt_tcp: mnt->flags |= NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; + mnt->timeo = 600; + mnt->retrans = 2; break; case Opt_xprt_rdma: /* vector side protocols to TCP */ mnt->flags |= NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; + mnt->timeo = 600; + mnt->retrans = 2; break; default: - errors++; - dfprintk(MOUNT, "NFS: unrecognized " - "transport protocol\n"); + goto out_unrec_xprt; } break; case Opt_mountproto: @@ -1219,19 +1063,16 @@ static int nfs_parse_mount_options(char *raw, break; case Opt_xprt_rdma: /* not used for side protocols */ default: - errors++; - dfprintk(MOUNT, "NFS: unrecognized " - "transport protocol\n"); + goto out_unrec_xprt; } break; case Opt_addr: string = match_strdup(args); if (string == NULL) goto out_nomem; - nfs_parse_ip_address(string, strlen(string), - (struct sockaddr *) - &mnt->nfs_server.address, - &mnt->nfs_server.addrlen); + nfs_parse_server_address(string, (struct sockaddr *) + &mnt->nfs_server.address, + &mnt->nfs_server.addrlen); kfree(string); break; case Opt_clientaddr: @@ -1252,33 +1093,24 @@ static int nfs_parse_mount_options(char *raw, string = match_strdup(args); if (string == NULL) goto out_nomem; - nfs_parse_ip_address(string, strlen(string), - (struct sockaddr *) - &mnt->mount_server.address, - &mnt->mount_server.addrlen); + nfs_parse_server_address(string, (struct sockaddr *) + &mnt->mount_server.address, + &mnt->mount_server.addrlen); kfree(string); break; - /* - * Special options - */ - case Opt_sloppy: - sloppy = 1; - dfprintk(MOUNT, "NFS: relaxing parsing rules\n"); - break; case Opt_userspace: case Opt_deprecated: - dfprintk(MOUNT, "NFS: ignoring mount option " - "'%s'\n", p); break; default: - errors++; - dfprintk(MOUNT, "NFS: unrecognized mount option " - "'%s'\n", p); + goto out_unknown; } } + nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, + mnt->nfs_server.port); + return 1; out_nomem: @@ -1288,6 +1120,21 @@ static int nfs_parse_mount_options(char *raw, free_secdata(secdata); printk(KERN_INFO "NFS: security options invalid: %d\n", rc); return 0; +out_unrec_vers: + printk(KERN_INFO "NFS: unrecognized NFS version number\n"); + return 0; + +out_unrec_xprt: + printk(KERN_INFO "NFS: unrecognized transport protocol\n"); + return 0; + +out_unrec_sec: + printk(KERN_INFO "NFS: unrecognized security flavor\n"); + return 0; + +out_unknown: + printk(KERN_INFO "NFS: unknown mount option: %s\n", p); + return 0; } /* @@ -1341,146 +1188,11 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, if (status == 0) return 0; - dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", + dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", hostname, status); return status; } -static int nfs_parse_simple_hostname(const char *dev_name, - char **hostname, size_t maxnamlen, - char **export_path, size_t maxpathlen) -{ - size_t len; - char *colon, *comma; - - colon = strchr(dev_name, ':'); - if (colon == NULL) - goto out_bad_devname; - - len = colon - dev_name; - if (len > maxnamlen) - goto out_hostname; - - /* N.B. caller will free nfs_server.hostname in all cases */ - *hostname = kstrndup(dev_name, len, GFP_KERNEL); - if (!*hostname) - goto out_nomem; - - /* kill possible hostname list: not supported */ - comma = strchr(*hostname, ','); - if (comma != NULL) { - if (comma == *hostname) - goto out_bad_devname; - *comma = '\0'; - } - - colon++; - len = strlen(colon); - if (len > maxpathlen) - goto out_path; - *export_path = kstrndup(colon, len, GFP_KERNEL); - if (!*export_path) - goto out_nomem; - - dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path); - return 0; - -out_bad_devname: - dfprintk(MOUNT, "NFS: device name not in host:path format\n"); - return -EINVAL; - -out_nomem: - dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); - return -ENOMEM; - -out_hostname: - dfprintk(MOUNT, "NFS: server hostname too long\n"); - return -ENAMETOOLONG; - -out_path: - dfprintk(MOUNT, "NFS: export pathname too long\n"); - return -ENAMETOOLONG; -} - -/* - * Hostname has square brackets around it because it contains one or - * more colons. We look for the first closing square bracket, and a - * colon must follow it. - */ -static int nfs_parse_protected_hostname(const char *dev_name, - char **hostname, size_t maxnamlen, - char **export_path, size_t maxpathlen) -{ - size_t len; - char *start, *end; - - start = (char *)(dev_name + 1); - - end = strchr(start, ']'); - if (end == NULL) - goto out_bad_devname; - if (*(end + 1) != ':') - goto out_bad_devname; - - len = end - start; - if (len > maxnamlen) - goto out_hostname; - - /* N.B. caller will free nfs_server.hostname in all cases */ - *hostname = kstrndup(start, len, GFP_KERNEL); - if (*hostname == NULL) - goto out_nomem; - - end += 2; - len = strlen(end); - if (len > maxpathlen) - goto out_path; - *export_path = kstrndup(end, len, GFP_KERNEL); - if (!*export_path) - goto out_nomem; - - return 0; - -out_bad_devname: - dfprintk(MOUNT, "NFS: device name not in host:path format\n"); - return -EINVAL; - -out_nomem: - dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); - return -ENOMEM; - -out_hostname: - dfprintk(MOUNT, "NFS: server hostname too long\n"); - return -ENAMETOOLONG; - -out_path: - dfprintk(MOUNT, "NFS: export pathname too long\n"); - return -ENAMETOOLONG; -} - -/* - * Split "dev_name" into "hostname:export_path". - * - * The leftmost colon demarks the split between the server's hostname - * and the export path. If the hostname starts with a left square - * bracket, then it may contain colons. - * - * Note: caller frees hostname and export path, even on error. - */ -static int nfs_parse_devname(const char *dev_name, - char **hostname, size_t maxnamlen, - char **export_path, size_t maxpathlen) -{ - if (*dev_name == '[') - return nfs_parse_protected_hostname(dev_name, - hostname, maxnamlen, - export_path, maxpathlen); - - return nfs_parse_simple_hostname(dev_name, - hostname, maxnamlen, - export_path, maxpathlen); -} - /* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle @@ -1510,14 +1222,16 @@ static int nfs_validate_mount_data(void *options, args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); args->rsize = NFS_MAX_FILE_IO_SIZE; args->wsize = NFS_MAX_FILE_IO_SIZE; - args->acregmin = NFS_DEF_ACREGMIN; - args->acregmax = NFS_DEF_ACREGMAX; - args->acdirmin = NFS_DEF_ACDIRMIN; - args->acdirmax = NFS_DEF_ACDIRMAX; + args->timeo = 600; + args->retrans = 2; + args->acregmin = 3; + args->acregmax = 60; + args->acdirmin = 30; + args->acdirmax = 60; args->mount_server.port = 0; /* autobind unless user sets port */ + args->mount_server.protocol = XPRT_TRANSPORT_UDP; args->nfs_server.port = 0; /* autobind unless user sets port */ args->nfs_server.protocol = XPRT_TRANSPORT_TCP; - args->auth_flavors[0] = RPC_AUTH_UNIX; switch (data->version) { case 1: @@ -1575,9 +1289,7 @@ static int nfs_validate_mount_data(void *options, args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); args->namlen = data->namlen; args->bsize = data->bsize; - - if (data->flags & NFS_MOUNT_SECFLAVOUR) - args->auth_flavors[0] = data->pseudoflavor; + args->auth_flavors[0] = data->pseudoflavor; if (!args->nfs_server.hostname) goto out_nomem; @@ -1609,6 +1321,8 @@ static int nfs_validate_mount_data(void *options, break; default: { + unsigned int len; + char *c; int status; if (nfs_parse_mount_options((char *)options, args) == 0) @@ -1618,22 +1332,21 @@ static int nfs_validate_mount_data(void *options, &args->nfs_server.address)) goto out_no_address; - nfs_set_port((struct sockaddr *)&args->nfs_server.address, - args->nfs_server.port); - - nfs_set_mount_transport_protocol(args); - - status = nfs_parse_devname(dev_name, - &args->nfs_server.hostname, - PAGE_SIZE, - &args->nfs_server.export_path, - NFS_MAXPATHLEN); - if (!status) - status = nfs_try_mount(args, mntfh); + c = strchr(dev_name, ':'); + if (c == NULL) + return -EINVAL; + len = c - dev_name; + /* N.B. caller will free nfs_server.hostname in all cases */ + args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); + if (!args->nfs_server.hostname) + goto out_nomem; - kfree(args->nfs_server.export_path); - args->nfs_server.export_path = NULL; + c++; + if (strlen(c) > NFS_MAXPATHLEN) + return -ENAMETOOLONG; + args->nfs_server.export_path = c; + status = nfs_try_mount(args, mntfh); if (status) return status; @@ -1641,6 +1354,9 @@ static int nfs_validate_mount_data(void *options, } } + if (!(args->flags & NFS_MOUNT_SECFLAVOUR)) + args->auth_flavors[0] = RPC_AUTH_UNIX; + #ifndef CONFIG_NFS_V3 if (args->flags & NFS_MOUNT_VER3) goto out_v3_not_compiled; @@ -1680,80 +1396,6 @@ static int nfs_validate_mount_data(void *options, return -EINVAL; } -static int -nfs_compare_remount_data(struct nfs_server *nfss, - struct nfs_parsed_mount_data *data) -{ - if (data->flags != nfss->flags || - data->rsize != nfss->rsize || - data->wsize != nfss->wsize || - data->retrans != nfss->client->cl_timeout->to_retries || - data->auth_flavors[0] != nfss->client->cl_auth->au_flavor || - data->acregmin != nfss->acregmin / HZ || - data->acregmax != nfss->acregmax / HZ || - data->acdirmin != nfss->acdirmin / HZ || - data->acdirmax != nfss->acdirmax / HZ || - data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) || - data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen || - memcmp(&data->nfs_server.address, &nfss->nfs_client->cl_addr, - data->nfs_server.addrlen) != 0) - return -EINVAL; - - return 0; -} - -static int -nfs_remount(struct super_block *sb, int *flags, char *raw_data) -{ - int error; - struct nfs_server *nfss = sb->s_fs_info; - struct nfs_parsed_mount_data *data; - struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data; - struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; - u32 nfsvers = nfss->nfs_client->rpc_ops->version; - - /* - * Userspace mount programs that send binary options generally send - * them populated with default values. We have no way to know which - * ones were explicitly specified. Fall back to legacy behavior and - * just return success. - */ - if ((nfsvers == 4 && options4->version == 1) || - (nfsvers <= 3 && options->version >= 1 && - options->version <= 6)) - return 0; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - /* fill out struct with values from existing mount */ - data->flags = nfss->flags; - data->rsize = nfss->rsize; - data->wsize = nfss->wsize; - data->retrans = nfss->client->cl_timeout->to_retries; - data->auth_flavors[0] = nfss->client->cl_auth->au_flavor; - data->acregmin = nfss->acregmin / HZ; - data->acregmax = nfss->acregmax / HZ; - data->acdirmin = nfss->acdirmin / HZ; - data->acdirmax = nfss->acdirmax / HZ; - data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; - data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; - memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, - data->nfs_server.addrlen); - - /* overwrite those values with any that were specified */ - error = nfs_parse_mount_options((char *)options, data); - if (error < 0) - goto out; - - /* compare new mount options with old ones */ - error = nfs_compare_remount_data(nfss, data); -out: - kfree(data); - return error; -} - /* * Initialise the common bits of the superblock */ @@ -2169,13 +1811,14 @@ static int nfs4_validate_mount_data(void *options, args->rsize = NFS_MAX_FILE_IO_SIZE; args->wsize = NFS_MAX_FILE_IO_SIZE; - args->acregmin = NFS_DEF_ACREGMIN; - args->acregmax = NFS_DEF_ACREGMAX; - args->acdirmin = NFS_DEF_ACDIRMIN; - args->acdirmax = NFS_DEF_ACDIRMAX; + args->timeo = 600; + args->retrans = 2; + args->acregmin = 3; + args->acregmax = 60; + args->acdirmin = 30; + args->acdirmax = 60; args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ - args->auth_flavors[0] = RPC_AUTH_UNIX; - args->auth_flavor_len = 0; + args->nfs_server.protocol = XPRT_TRANSPORT_TCP; switch (data->version) { case 1: @@ -2191,13 +1834,18 @@ static int nfs4_validate_mount_data(void *options, &args->nfs_server.address)) goto out_no_address; - if (data->auth_flavourlen) { - if (data->auth_flavourlen > 1) - goto out_inval_auth; + switch (data->auth_flavourlen) { + case 0: + args->auth_flavors[0] = RPC_AUTH_UNIX; + break; + case 1: if (copy_from_user(&args->auth_flavors[0], data->auth_flavours, sizeof(args->auth_flavors[0]))) return -EFAULT; + break; + default: + goto out_inval_auth; } c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); @@ -2231,11 +1879,10 @@ static int nfs4_validate_mount_data(void *options, args->acdirmin = data->acdirmin; args->acdirmax = data->acdirmax; args->nfs_server.protocol = data->proto; - nfs_validate_transport_protocol(args); break; default: { - int status; + unsigned int len; if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; @@ -2244,25 +1891,44 @@ static int nfs4_validate_mount_data(void *options, &args->nfs_server.address)) return -EINVAL; - nfs_set_port((struct sockaddr *)&args->nfs_server.address, - args->nfs_server.port); + switch (args->auth_flavor_len) { + case 0: + args->auth_flavors[0] = RPC_AUTH_UNIX; + break; + case 1: + break; + default: + goto out_inval_auth; + } - nfs_validate_transport_protocol(args); + /* + * Split "dev_name" into "hostname:mntpath". + */ + c = strchr(dev_name, ':'); + if (c == NULL) + return -EINVAL; + /* while calculating len, pretend ':' is '\0' */ + len = c - dev_name; + if (len > NFS4_MAXNAMLEN) + return -ENAMETOOLONG; + /* N.B. caller will free nfs_server.hostname in all cases */ + args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); + if (!args->nfs_server.hostname) + goto out_nomem; - if (args->auth_flavor_len > 1) - goto out_inval_auth; + c++; /* step over the ':' */ + len = strlen(c); + if (len > NFS4_MAXPATHLEN) + return -ENAMETOOLONG; + args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); + if (!args->nfs_server.export_path) + goto out_nomem; + + dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); if (args->client_address == NULL) goto out_no_client_address; - status = nfs_parse_devname(dev_name, - &args->nfs_server.hostname, - NFS4_MAXNAMLEN, - &args->nfs_server.export_path, - NFS4_MAXPATHLEN); - if (status < 0) - return status; - break; } } @@ -2278,6 +1944,10 @@ static int nfs4_validate_mount_data(void *options, data->auth_flavourlen); return -EINVAL; +out_nomem: + dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); + return -ENOMEM; + out_no_address: dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); return -EINVAL; diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index 3229e217c773..f333848fd3be 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -34,6 +34,9 @@ /* * Local function declarations */ +static struct nfs_page * nfs_update_request(struct nfs_open_context*, + struct page *, + unsigned int, unsigned int); static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc, struct inode *inode, int ioflags); static void nfs_redirty_request(struct nfs_page *req); @@ -133,21 +136,16 @@ static struct nfs_page *nfs_page_find_request(struct page *page) static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) { struct inode *inode = page->mapping->host; - loff_t end, i_size; - pgoff_t end_index; + loff_t end, i_size = i_size_read(inode); + pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; - spin_lock(&inode->i_lock); - i_size = i_size_read(inode); - end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; if (i_size > 0 && page->index < end_index) - goto out; + return; end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); if (i_size >= end) - goto out; - i_size_write(inode, end); + return; nfs_inc_stats(inode, NFSIOS_EXTENDWRITE); -out: - spin_unlock(&inode->i_lock); + i_size_write(inode, end); } /* A writeback failed: mark the page as bad, and invalidate the page cache */ @@ -171,6 +169,29 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int SetPageUptodate(page); } +static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, + unsigned int offset, unsigned int count) +{ + struct nfs_page *req; + int ret; + + for (;;) { + req = nfs_update_request(ctx, page, offset, count); + if (!IS_ERR(req)) + break; + ret = PTR_ERR(req); + if (ret != -EBUSY) + return ret; + ret = nfs_wb_page(page->mapping->host, page); + if (ret != 0) + return ret; + } + /* Update file length */ + nfs_grow_file(page, offset, count); + nfs_clear_page_tag_locked(req); + return 0; +} + static int wb_priority(struct writeback_control *wbc) { if (wbc->for_reclaim) @@ -247,9 +268,12 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, return ret; spin_lock(&inode->i_lock); } - if (test_bit(PG_CLEAN, &req->wb_flags)) { + if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { + /* This request is marked for commit */ spin_unlock(&inode->i_lock); - BUG(); + nfs_clear_page_tag_locked(req); + nfs_pageio_complete(pgio); + return 0; } if (nfs_set_page_writeback(page) != 0) { spin_unlock(&inode->i_lock); @@ -331,19 +355,11 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) /* * Insert a write request into an inode */ -static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) +static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(inode); int error; - error = radix_tree_preload(GFP_NOFS); - if (error != 0) - goto out; - - /* Lock the request! */ - nfs_lock_request_dontget(req); - - spin_lock(&inode->i_lock); error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); BUG_ON(error); if (!nfsi->npages) { @@ -357,10 +373,6 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) kref_get(&req->wb_kref); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); - spin_unlock(&inode->i_lock); - radix_tree_preload_end(); -out: - return error; } /* @@ -393,6 +405,19 @@ nfs_mark_request_dirty(struct nfs_page *req) __set_page_dirty_nobuffers(req->wb_page); } +/* + * Check if a request is dirty + */ +static inline int +nfs_dirty_request(struct nfs_page *req) +{ + struct page *page = req->wb_page; + + if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags)) + return 0; + return !PageWriteback(page); +} + #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) /* * Add a request to the inode's commit list. @@ -405,7 +430,7 @@ nfs_mark_request_commit(struct nfs_page *req) spin_lock(&inode->i_lock); nfsi->ncommit++; - set_bit(PG_CLEAN, &(req)->wb_flags); + set_bit(PG_NEED_COMMIT, &(req)->wb_flags); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_COMMIT); @@ -415,19 +440,6 @@ nfs_mark_request_commit(struct nfs_page *req) __mark_inode_dirty(inode, I_DIRTY_DATASYNC); } -static int -nfs_clear_request_commit(struct nfs_page *req) -{ - struct page *page = req->wb_page; - - if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) { - dec_zone_page_state(page, NR_UNSTABLE_NFS); - dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); - return 1; - } - return 0; -} - static inline int nfs_write_need_commit(struct nfs_write_data *data) { @@ -437,7 +449,7 @@ int nfs_write_need_commit(struct nfs_write_data *data) static inline int nfs_reschedule_unstable_write(struct nfs_page *req) { - if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { + if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { nfs_mark_request_commit(req); return 1; } @@ -453,12 +465,6 @@ nfs_mark_request_commit(struct nfs_page *req) { } -static inline int -nfs_clear_request_commit(struct nfs_page *req) -{ - return 0; -} - static inline int nfs_write_need_commit(struct nfs_write_data *data) { @@ -516,8 +522,11 @@ static void nfs_cancel_commit_list(struct list_head *head) while(!list_empty(head)) { req = nfs_list_entry(head->next); + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, + BDI_RECLAIMABLE); nfs_list_remove_request(req); - nfs_clear_request_commit(req); + clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); nfs_inode_remove_request(req); nfs_unlock_request(req); } @@ -555,122 +564,108 @@ static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pg #endif /* - * Search for an existing write request, and attempt to update - * it to reflect a new dirty region on a given page. + * Try to update any existing write request, or create one if there is none. + * In order to match, the request's credentials must match those of + * the calling process. * - * If the attempt fails, then the existing request is flushed out - * to disk. + * Note: Should always be called with the Page Lock held! */ -static struct nfs_page *nfs_try_to_update_request(struct inode *inode, - struct page *page, - unsigned int offset, - unsigned int bytes) +static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, + struct page *page, unsigned int offset, unsigned int bytes) { - struct nfs_page *req; - unsigned int rqend; - unsigned int end; - int error; - - if (!PagePrivate(page)) - return NULL; + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + struct nfs_page *req, *new = NULL; + pgoff_t rqend, end; end = offset + bytes; - spin_lock(&inode->i_lock); for (;;) { - req = nfs_page_find_request_locked(page); - if (req == NULL) - goto out_unlock; - - rqend = req->wb_offset + req->wb_bytes; - /* - * Tell the caller to flush out the request if - * the offsets are non-contiguous. - * Note: nfs_flush_incompatible() will already - * have flushed out requests having wrong owners. + /* Loop over all inode entries and see if we find + * A request for the page we wish to update */ - if (offset > rqend - || end < req->wb_offset) - goto out_flushme; + if (new) { + if (radix_tree_preload(GFP_NOFS)) { + nfs_release_request(new); + return ERR_PTR(-ENOMEM); + } + } - if (nfs_set_page_tag_locked(req)) + spin_lock(&inode->i_lock); + req = nfs_page_find_request_locked(page); + if (req) { + if (!nfs_set_page_tag_locked(req)) { + int error; + + spin_unlock(&inode->i_lock); + error = nfs_wait_on_request(req); + nfs_release_request(req); + if (error < 0) { + if (new) { + radix_tree_preload_end(); + nfs_release_request(new); + } + return ERR_PTR(error); + } + continue; + } + spin_unlock(&inode->i_lock); + if (new) { + radix_tree_preload_end(); + nfs_release_request(new); + } break; + } - /* The request is locked, so wait and then retry */ + if (new) { + nfs_lock_request_dontget(new); + nfs_inode_add_request(inode, new); + spin_unlock(&inode->i_lock); + radix_tree_preload_end(); + req = new; + goto zero_page; + } spin_unlock(&inode->i_lock); - error = nfs_wait_on_request(req); - nfs_release_request(req); - if (error != 0) - goto out_err; - spin_lock(&inode->i_lock); + + new = nfs_create_request(ctx, inode, page, offset, bytes); + if (IS_ERR(new)) + return new; } - if (nfs_clear_request_commit(req)) - radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, - req->wb_index, NFS_PAGE_TAG_COMMIT); + /* We have a request for our page. + * If the creds don't match, or the + * page addresses don't match, + * tell the caller to wait on the conflicting + * request. + */ + rqend = req->wb_offset + req->wb_bytes; + if (req->wb_context != ctx + || req->wb_page != page + || !nfs_dirty_request(req) + || offset > rqend || end < req->wb_offset) { + nfs_clear_page_tag_locked(req); + return ERR_PTR(-EBUSY); + } /* Okay, the request matches. Update the region */ if (offset < req->wb_offset) { req->wb_offset = offset; req->wb_pgbase = offset; + req->wb_bytes = max(end, rqend) - req->wb_offset; + goto zero_page; } + if (end > rqend) req->wb_bytes = end - req->wb_offset; - else - req->wb_bytes = rqend - req->wb_offset; -out_unlock: - spin_unlock(&inode->i_lock); - return req; -out_flushme: - spin_unlock(&inode->i_lock); - nfs_release_request(req); - error = nfs_wb_page(inode, page); -out_err: - return ERR_PTR(error); -} -/* - * Try to update an existing write request, or create one if there is none. - * - * Note: Should always be called with the Page Lock held to prevent races - * if we have to add a new request. Also assumes that the caller has - * already called nfs_flush_incompatible() if necessary. - */ -static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx, - struct page *page, unsigned int offset, unsigned int bytes) -{ - struct inode *inode = page->mapping->host; - struct nfs_page *req; - int error; - - req = nfs_try_to_update_request(inode, page, offset, bytes); - if (req != NULL) - goto out; - req = nfs_create_request(ctx, inode, page, offset, bytes); - if (IS_ERR(req)) - goto out; - error = nfs_inode_add_request(inode, req); - if (error != 0) { - nfs_release_request(req); - req = ERR_PTR(error); - } -out: return req; -} - -static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, - unsigned int offset, unsigned int count) -{ - struct nfs_page *req; - - req = nfs_setup_write_request(ctx, page, offset, count); - if (IS_ERR(req)) - return PTR_ERR(req); - /* Update file length */ - nfs_grow_file(page, offset, count); - nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); - nfs_clear_page_tag_locked(req); - return 0; +zero_page: + /* If this page might potentially be marked as up to date, + * then we need to zero any uninitalised data. */ + if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE + && !PageUptodate(req->wb_page)) + zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE); + return req; } int nfs_flush_incompatible(struct file *file, struct page *page) @@ -690,7 +685,8 @@ int nfs_flush_incompatible(struct file *file, struct page *page) req = nfs_page_find_request(page); if (req == NULL) return 0; - do_flush = req->wb_page != page || req->wb_context != ctx; + do_flush = req->wb_page != page || req->wb_context != ctx + || !nfs_dirty_request(req); nfs_release_request(req); if (!do_flush) return 0; @@ -725,10 +721,10 @@ int nfs_updatepage(struct file *file, struct page *page, nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); - dprintk("NFS: nfs_updatepage(%s/%s %d@%lld)\n", + dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, count, - (long long)(page_offset(page) + offset)); + (long long)(page_offset(page) +offset)); /* If we're not using byte range locks, and we know the page * is up to date, it may be more efficient to extend the write @@ -748,7 +744,7 @@ int nfs_updatepage(struct file *file, struct page *page, else __set_page_dirty_nobuffers(page); - dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", + dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", status, (long long)i_size_read(inode)); return status; } @@ -756,7 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, static void nfs_writepage_release(struct nfs_page *req) { - if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { + if (PageError(req->wb_page)) { + nfs_end_page_writeback(req->wb_page); + nfs_inode_remove_request(req); + } else if (!nfs_reschedule_unstable_write(req)) { + /* Set the PG_uptodate flag */ + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes); nfs_end_page_writeback(req->wb_page); nfs_inode_remove_request(req); } else @@ -833,7 +834,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, NFS_PROTO(inode)->write_setup(data, &msg); dprintk("NFS: %5u initiated write call " - "(req %s/%lld, %u bytes @ offset %llu)\n", + "(req %s/%Ld, %u bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), @@ -977,13 +978,13 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) { struct nfs_write_data *data = calldata; + struct nfs_page *req = data->req; - dprintk("NFS: %5u write(%s/%lld %d@%lld)", - task->tk_pid, - data->req->wb_context->path.dentry->d_inode->i_sb->s_id, - (long long) - NFS_FILEID(data->req->wb_context->path.dentry->d_inode), - data->req->wb_bytes, (long long)req_offset(data->req)); + dprintk("NFS: write (%s/%Ld %d@%Ld)", + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), + req->wb_bytes, + (long long)req_offset(req)); nfs_writeback_done(task, data); } @@ -1057,8 +1058,7 @@ static void nfs_writeback_release_full(void *calldata) nfs_list_remove_request(req); - dprintk("NFS: %5u write (%s/%lld %d@%lld)", - data->task.tk_pid, + dprintk("NFS: write (%s/%Ld %d@%Ld)", req->wb_context->path.dentry->d_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, @@ -1078,6 +1078,8 @@ static void nfs_writeback_release_full(void *calldata) dprintk(" marked for commit\n"); goto next; } + /* Set the PG_uptodate flag? */ + nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); dprintk(" OK\n"); remove_request: nfs_end_page_writeback(page); @@ -1131,7 +1133,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) static unsigned long complain; if (time_before(complain, jiffies)) { - dprintk("NFS: faulty NFS server %s:" + dprintk("NFS: faulty NFS server %s:" " (committed = %d) != (stable = %d)\n", NFS_SERVER(data->inode)->nfs_client->cl_hostname, resp->verf->committed, argp->stable); @@ -1295,9 +1297,12 @@ static void nfs_commit_release(void *calldata) while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); - nfs_clear_request_commit(req); + clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, + BDI_RECLAIMABLE); - dprintk("NFS: commit (%s/%lld %d@%lld)", + dprintk("NFS: commit (%s/%Ld %d@%Ld)", req->wb_context->path.dentry->d_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, @@ -1313,6 +1318,9 @@ static void nfs_commit_release(void *calldata) * returned by the server against all stored verfs. */ if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { /* We have a match */ + /* Set the PG_uptodate flag */ + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, + req->wb_bytes); nfs_inode_remove_request(req); dprintk(" OK\n"); goto next; @@ -1471,7 +1479,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) req = nfs_page_find_request(page); if (req == NULL) goto out; - if (test_bit(PG_CLEAN, &req->wb_flags)) { + if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { nfs_release_request(req); break; } diff --git a/trunk/fs/nfsd/nfs4callback.c b/trunk/fs/nfsd/nfs4callback.c index 702fa577aa6e..4d4760e687c3 100644 --- a/trunk/fs/nfsd/nfs4callback.c +++ b/trunk/fs/nfsd/nfs4callback.c @@ -381,7 +381,7 @@ static int do_probe_callback(void *data) .program = &cb_program, .version = nfs_cb_version[1]->number, .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ - .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), + .flags = (RPC_CLNT_CREATE_NOPING), }; struct rpc_message msg = { .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], diff --git a/trunk/include/linux/blkdev.h b/trunk/include/linux/blkdev.h index 88d68081a0f1..32a441b05fd5 100644 --- a/trunk/include/linux/blkdev.h +++ b/trunk/include/linux/blkdev.h @@ -985,9 +985,6 @@ static inline int bdev_integrity_enabled(struct block_device *bdev, int rw) static inline int blk_integrity_rq(struct request *rq) { - if (rq->bio == NULL) - return 0; - return bio_integrity(rq->bio); } diff --git a/trunk/include/linux/inet.h b/trunk/include/linux/inet.h index 4cca05c9678e..1354080cf8cf 100644 --- a/trunk/include/linux/inet.h +++ b/trunk/include/linux/inet.h @@ -44,13 +44,6 @@ #include -/* - * These mimic similar macros defined in user-space for inet_ntop(3). - * See /usr/include/netinet/in.h . - */ -#define INET_ADDRSTRLEN (16) -#define INET6_ADDRSTRLEN (48) - extern __be32 in_aton(const char *str); extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); diff --git a/trunk/include/linux/nfs_fs.h b/trunk/include/linux/nfs_fs.h index 29d261918734..27d6a8d98cef 100644 --- a/trunk/include/linux/nfs_fs.h +++ b/trunk/include/linux/nfs_fs.h @@ -12,19 +12,9 @@ #include /* Default timeout values */ -#define NFS_DEF_UDP_TIMEO (11) -#define NFS_DEF_UDP_RETRANS (3) -#define NFS_DEF_TCP_TIMEO (600) -#define NFS_DEF_TCP_RETRANS (2) - #define NFS_MAX_UDP_TIMEOUT (60*HZ) #define NFS_MAX_TCP_TIMEOUT (600*HZ) -#define NFS_DEF_ACREGMIN (3) -#define NFS_DEF_ACREGMAX (60) -#define NFS_DEF_ACDIRMIN (30) -#define NFS_DEF_ACDIRMAX (60) - /* * When flushing a cluster of dirty pages, there can be different * strategies: diff --git a/trunk/include/linux/nfs_iostat.h b/trunk/include/linux/nfs_iostat.h deleted file mode 100644 index 1cb9a3fed2b3..000000000000 --- a/trunk/include/linux/nfs_iostat.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * User-space visible declarations for NFS client per-mount - * point statistics - * - * Copyright (C) 2005, 2006 Chuck Lever - * - * NFS client per-mount statistics provide information about the - * health of the NFS client and the health of each NFS mount point. - * Generally these are not for detailed problem diagnosis, but - * simply to indicate that there is a problem. - * - * These counters are not meant to be human-readable, but are meant - * to be integrated into system monitoring tools such as "sar" and - * "iostat". As such, the counters are sampled by the tools over - * time, and are never zeroed after a file system is mounted. - * Moving averages can be computed by the tools by taking the - * difference between two instantaneous samples and dividing that - * by the time between the samples. - */ - -#ifndef _LINUX_NFS_IOSTAT -#define _LINUX_NFS_IOSTAT - -#define NFS_IOSTAT_VERS "1.0" - -/* - * NFS byte counters - * - * 1. SERVER - the number of payload bytes read from or written - * to the server by the NFS client via an NFS READ or WRITE - * request. - * - * 2. NORMAL - the number of bytes read or written by applications - * via the read(2) and write(2) system call interfaces. - * - * 3. DIRECT - the number of bytes read or written from files - * opened with the O_DIRECT flag. - * - * These counters give a view of the data throughput into and out - * of the NFS client. Comparing the number of bytes requested by - * an application with the number of bytes the client requests from - * the server can provide an indication of client efficiency - * (per-op, cache hits, etc). - * - * These counters can also help characterize which access methods - * are in use. DIRECT by itself shows whether there is any O_DIRECT - * traffic. NORMAL + DIRECT shows how much data is going through - * the system call interface. A large amount of SERVER traffic - * without much NORMAL or DIRECT traffic shows that applications - * are using mapped files. - * - * NFS page counters - * - * These count the number of pages read or written via nfs_readpage(), - * nfs_readpages(), or their write equivalents. - * - * NB: When adding new byte counters, please include the measured - * units in the name of each byte counter to help users of this - * interface determine what exactly is being counted. - */ -enum nfs_stat_bytecounters { - NFSIOS_NORMALREADBYTES = 0, - NFSIOS_NORMALWRITTENBYTES, - NFSIOS_DIRECTREADBYTES, - NFSIOS_DIRECTWRITTENBYTES, - NFSIOS_SERVERREADBYTES, - NFSIOS_SERVERWRITTENBYTES, - NFSIOS_READPAGES, - NFSIOS_WRITEPAGES, - __NFSIOS_BYTESMAX, -}; - -/* - * NFS event counters - * - * These counters provide a low-overhead way of monitoring client - * activity without enabling NFS trace debugging. The counters - * show the rate at which VFS requests are made, and how often the - * client invalidates its data and attribute caches. This allows - * system administrators to monitor such things as how close-to-open - * is working, and answer questions such as "why are there so many - * GETATTR requests on the wire?" - * - * They also count anamolous events such as short reads and writes, - * silly renames due to close-after-delete, and operations that - * change the size of a file (such operations can often be the - * source of data corruption if applications aren't using file - * locking properly). - */ -enum nfs_stat_eventcounters { - NFSIOS_INODEREVALIDATE = 0, - NFSIOS_DENTRYREVALIDATE, - NFSIOS_DATAINVALIDATE, - NFSIOS_ATTRINVALIDATE, - NFSIOS_VFSOPEN, - NFSIOS_VFSLOOKUP, - NFSIOS_VFSACCESS, - NFSIOS_VFSUPDATEPAGE, - NFSIOS_VFSREADPAGE, - NFSIOS_VFSREADPAGES, - NFSIOS_VFSWRITEPAGE, - NFSIOS_VFSWRITEPAGES, - NFSIOS_VFSGETDENTS, - NFSIOS_VFSSETATTR, - NFSIOS_VFSFLUSH, - NFSIOS_VFSFSYNC, - NFSIOS_VFSLOCK, - NFSIOS_VFSRELEASE, - NFSIOS_CONGESTIONWAIT, - NFSIOS_SETATTRTRUNC, - NFSIOS_EXTENDWRITE, - NFSIOS_SILLYRENAME, - NFSIOS_SHORTREAD, - NFSIOS_SHORTWRITE, - NFSIOS_DELAY, - __NFSIOS_COUNTSMAX, -}; - -#endif /* _LINUX_NFS_IOSTAT */ diff --git a/trunk/include/linux/nfs_page.h b/trunk/include/linux/nfs_page.h index 3c60685d972b..a1676e19e491 100644 --- a/trunk/include/linux/nfs_page.h +++ b/trunk/include/linux/nfs_page.h @@ -27,12 +27,9 @@ /* * Valid flags for a dirty buffer */ -enum { - PG_BUSY = 0, - PG_CLEAN, - PG_NEED_COMMIT, - PG_NEED_RESCHED, -}; +#define PG_BUSY 0 +#define PG_NEED_COMMIT 1 +#define PG_NEED_RESCHED 2 struct nfs_inode; struct nfs_page { diff --git a/trunk/include/linux/nfs_xdr.h b/trunk/include/linux/nfs_xdr.h index 8c77c11224d1..24263bb8e0be 100644 --- a/trunk/include/linux/nfs_xdr.h +++ b/trunk/include/linux/nfs_xdr.h @@ -829,8 +829,9 @@ struct nfs_rpc_ops { int (*write_done) (struct rpc_task *, struct nfs_write_data *); void (*commit_setup) (struct nfs_write_data *, struct rpc_message *); int (*commit_done) (struct rpc_task *, struct nfs_write_data *); + int (*file_open) (struct inode *, struct file *); + int (*file_release) (struct inode *, struct file *); int (*lock)(struct file *, int, struct file_lock *); - int (*lock_check_bounds)(const struct file_lock *); void (*clear_acl_cache)(struct inode *); }; diff --git a/trunk/include/linux/sunrpc/clnt.h b/trunk/include/linux/sunrpc/clnt.h index e5bfe01ee305..6fff7f82ef12 100644 --- a/trunk/include/linux/sunrpc/clnt.h +++ b/trunk/include/linux/sunrpc/clnt.h @@ -42,8 +42,7 @@ struct rpc_clnt { unsigned int cl_softrtry : 1,/* soft timeouts */ cl_discrtry : 1,/* disconnect before retry */ - cl_autobind : 1,/* use getport() */ - cl_chatty : 1;/* be verbose */ + cl_autobind : 1;/* use getport() */ struct rpc_rtt * cl_rtt; /* RTO estimator data */ const struct rpc_timeout *cl_timeout; /* Timeout strategy */ @@ -115,7 +114,6 @@ struct rpc_create_args { #define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3) #define RPC_CLNT_CREATE_NOPING (1UL << 4) #define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) -#define RPC_CLNT_CREATE_QUIET (1UL << 6) struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, @@ -125,9 +123,6 @@ void rpc_shutdown_client(struct rpc_clnt *); void rpc_release_client(struct rpc_clnt *); int rpcb_register(u32, u32, int, unsigned short, int *); -int rpcb_v4_register(const u32 program, const u32 version, - const struct sockaddr *address, - const char *netid, int *result); int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int); void rpcb_getport_async(struct rpc_task *); diff --git a/trunk/include/linux/sunrpc/sched.h b/trunk/include/linux/sunrpc/sched.h index 64981a2f1cae..d1a5c8c1a0f1 100644 --- a/trunk/include/linux/sunrpc/sched.h +++ b/trunk/include/linux/sunrpc/sched.h @@ -135,6 +135,7 @@ struct rpc_task_setup { #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) +#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) #define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) #define RPC_TASK_RUNNING 0 diff --git a/trunk/net/sunrpc/auth_gss/auth_gss.c b/trunk/net/sunrpc/auth_gss/auth_gss.c index 834a83199bdf..cc12d5f5d5da 100644 --- a/trunk/net/sunrpc/auth_gss/auth_gss.c +++ b/trunk/net/sunrpc/auth_gss/auth_gss.c @@ -63,11 +63,22 @@ static const struct rpc_credops gss_nullops; # define RPCDBG_FACILITY RPCDBG_AUTH #endif -#define GSS_CRED_SLACK 1024 +#define NFS_NGROUPS 16 + +#define GSS_CRED_SLACK 1024 /* XXX: unused */ /* length of a krb5 verifier (48), plus data added before arguments when * using integrity (two 4-byte integers): */ #define GSS_VERF_SLACK 100 +/* XXX this define must match the gssd define +* as it is passed to gssd to signal the use of +* machine creds should be part of the shared rpc interface */ + +#define CA_RUN_AS_MACHINE 0x00000200 + +/* dump the buffer in `emacs-hexl' style */ +#define isprint(c) ((c > 0x1f) && (c < 0x7f)) + struct gss_auth { struct kref kref; struct rpc_auth rpc_auth; @@ -135,7 +146,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest) q = (const void *)((const char *)p + len); if (unlikely(q > end || q < p)) return ERR_PTR(-EFAULT); - dest->data = kmemdup(p, len, GFP_NOFS); + dest->data = kmemdup(p, len, GFP_KERNEL); if (unlikely(dest->data == NULL)) return ERR_PTR(-ENOMEM); dest->len = len; @@ -160,7 +171,7 @@ gss_alloc_context(void) { struct gss_cl_ctx *ctx; - ctx = kzalloc(sizeof(*ctx), GFP_NOFS); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { ctx->gc_proc = RPC_GSS_PROC_DATA; ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */ @@ -261,7 +272,7 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) return NULL; } -/* Try to add an upcall to the pipefs queue. +/* Try to add a upcall to the pipefs queue. * If an upcall owned by our uid already exists, then we return a reference * to that upcall instead of adding the new upcall. */ @@ -330,7 +341,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) { struct gss_upcall_msg *gss_msg; - gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); + gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL); if (gss_msg != NULL) { INIT_LIST_HEAD(&gss_msg->list); rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); @@ -482,6 +493,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) { const void *p, *end; void *buf; + struct rpc_clnt *clnt; struct gss_upcall_msg *gss_msg; struct inode *inode = filp->f_path.dentry->d_inode; struct gss_cl_ctx *ctx; @@ -491,10 +503,11 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) if (mlen > MSG_BUF_MAXSIZE) goto out; err = -ENOMEM; - buf = kmalloc(mlen, GFP_NOFS); + buf = kmalloc(mlen, GFP_KERNEL); if (!buf) goto out; + clnt = RPC_I(inode)->private; err = -EFAULT; if (copy_from_user(buf, src, mlen)) goto err; @@ -793,7 +806,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", acred->uid, auth->au_flavor); - if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS))) + if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL))) goto out_err; rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops); diff --git a/trunk/net/sunrpc/auth_gss/gss_krb5_mech.c b/trunk/net/sunrpc/auth_gss/gss_krb5_mech.c index ef45eba22485..60c3dba545d7 100644 --- a/trunk/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/trunk/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -70,7 +70,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) q = (const void *)((const char *)p + len); if (unlikely(q > end || q < p)) return ERR_PTR(-EFAULT); - res->data = kmemdup(p, len, GFP_NOFS); + res->data = kmemdup(p, len, GFP_KERNEL); if (unlikely(res->data == NULL)) return ERR_PTR(-ENOMEM); res->len = len; @@ -131,7 +131,7 @@ gss_import_sec_context_kerberos(const void *p, struct krb5_ctx *ctx; int tmp; - if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) + if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); diff --git a/trunk/net/sunrpc/auth_gss/gss_spkm3_mech.c b/trunk/net/sunrpc/auth_gss/gss_spkm3_mech.c index 035e1dd6af1b..5deb4b6e4514 100644 --- a/trunk/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/trunk/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -76,7 +76,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) q = (const void *)((const char *)p + len); if (unlikely(q > end || q < p)) return ERR_PTR(-EFAULT); - res->data = kmemdup(p, len, GFP_NOFS); + res->data = kmemdup(p, len, GFP_KERNEL); if (unlikely(res->data == NULL)) return ERR_PTR(-ENOMEM); return q; @@ -90,7 +90,7 @@ gss_import_sec_context_spkm3(const void *p, size_t len, struct spkm3_ctx *ctx; int version; - if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) + if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; p = simple_get_bytes(p, end, &version, sizeof(version)); diff --git a/trunk/net/sunrpc/auth_gss/gss_spkm3_token.c b/trunk/net/sunrpc/auth_gss/gss_spkm3_token.c index 3308157436d2..6cdd241ad267 100644 --- a/trunk/net/sunrpc/auth_gss/gss_spkm3_token.c +++ b/trunk/net/sunrpc/auth_gss/gss_spkm3_token.c @@ -90,7 +90,7 @@ asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits) int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen) { - if (!(out->data = kzalloc(explen,GFP_NOFS))) + if (!(out->data = kzalloc(explen,GFP_KERNEL))) return 0; out->len = explen; memcpy(out->data, in, enclen); diff --git a/trunk/net/sunrpc/auth_unix.c b/trunk/net/sunrpc/auth_unix.c index 46b2647c5bd2..44920b90bdc4 100644 --- a/trunk/net/sunrpc/auth_unix.c +++ b/trunk/net/sunrpc/auth_unix.c @@ -66,7 +66,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", acred->uid, acred->gid); - if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS))) + if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL))) return ERR_PTR(-ENOMEM); rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); diff --git a/trunk/net/sunrpc/clnt.c b/trunk/net/sunrpc/clnt.c index 76739e928d0d..8945307556ec 100644 --- a/trunk/net/sunrpc/clnt.c +++ b/trunk/net/sunrpc/clnt.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -59,6 +58,7 @@ static void call_start(struct rpc_task *task); static void call_reserve(struct rpc_task *task); static void call_reserveresult(struct rpc_task *task); static void call_allocate(struct rpc_task *task); +static void call_encode(struct rpc_task *task); static void call_decode(struct rpc_task *task); static void call_bind(struct rpc_task *task); static void call_bind_status(struct rpc_task *task); @@ -70,9 +70,9 @@ static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); static void call_connect(struct rpc_task *task); static void call_connect_status(struct rpc_task *task); +static __be32 * call_header(struct rpc_task *task); +static __be32 * call_verify(struct rpc_task *task); -static __be32 *rpc_encode_header(struct rpc_task *task); -static __be32 *rpc_verify_header(struct rpc_task *task); static int rpc_ping(struct rpc_clnt *clnt, int flags); static void rpc_register_client(struct rpc_clnt *clnt) @@ -324,8 +324,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) clnt->cl_autobind = 1; if (args->flags & RPC_CLNT_CREATE_DISCRTRY) clnt->cl_discrtry = 1; - if (!(args->flags & RPC_CLNT_CREATE_QUIET)) - clnt->cl_chatty = 1; return clnt; } @@ -692,21 +690,6 @@ rpc_restart_call(struct rpc_task *task) } EXPORT_SYMBOL_GPL(rpc_restart_call); -#ifdef RPC_DEBUG -static const char *rpc_proc_name(const struct rpc_task *task) -{ - const struct rpc_procinfo *proc = task->tk_msg.rpc_proc; - - if (proc) { - if (proc->p_name) - return proc->p_name; - else - return "NULL"; - } else - return "no proc"; -} -#endif - /* * 0. Initial state * @@ -718,9 +701,9 @@ call_start(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid, + dprintk("RPC: %5u call_start %s%d proc %d (%s)\n", task->tk_pid, clnt->cl_protname, clnt->cl_vers, - rpc_proc_name(task), + task->tk_msg.rpc_proc->p_proc, (RPC_IS_ASYNC(task) ? "async" : "sync")); /* Increment call count */ @@ -878,7 +861,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) * 3. Encode arguments of an RPC call */ static void -rpc_xdr_encode(struct rpc_task *task) +call_encode(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; kxdrproc_t encode; @@ -893,19 +876,23 @@ rpc_xdr_encode(struct rpc_task *task) (char *)req->rq_buffer + req->rq_callsize, req->rq_rcvsize); - p = rpc_encode_header(task); - if (p == NULL) { - printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n"); + /* Encode header and provided arguments */ + encode = task->tk_msg.rpc_proc->p_encode; + if (!(p = call_header(task))) { + printk(KERN_INFO "RPC: call_header failed, exit EIO\n"); rpc_exit(task, -EIO); return; } - - encode = task->tk_msg.rpc_proc->p_encode; if (encode == NULL) return; task->tk_status = rpcauth_wrap_req(task, encode, req, p, task->tk_msg.rpc_argp); + if (task->tk_status == -ENOMEM) { + /* XXX: Is this sane? */ + rpc_delay(task, 3*HZ); + task->tk_status = -EAGAIN; + } } /* @@ -942,9 +929,11 @@ call_bind_status(struct rpc_task *task) } switch (task->tk_status) { - case -ENOMEM: - dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); - rpc_delay(task, HZ >> 2); + case -EAGAIN: + dprintk("RPC: %5u rpcbind waiting for another request " + "to finish\n", task->tk_pid); + /* avoid busy-waiting here -- could be a network outage. */ + rpc_delay(task, 5*HZ); goto retry_timeout; case -EACCES: dprintk("RPC: %5u remote rpcbind: RPC program/version " @@ -1057,16 +1046,10 @@ call_transmit(struct rpc_task *task) /* Encode here so that rpcsec_gss can use correct sequence number. */ if (rpc_task_need_encode(task)) { BUG_ON(task->tk_rqstp->rq_bytes_sent != 0); - rpc_xdr_encode(task); + call_encode(task); /* Did the encode result in an error condition? */ - if (task->tk_status != 0) { - /* Was the error nonfatal? */ - if (task->tk_status == -EAGAIN) - rpc_delay(task, HZ >> 4); - else - rpc_exit(task, task->tk_status); + if (task->tk_status != 0) return; - } } xprt_transmit(task); if (task->tk_status < 0) @@ -1149,8 +1132,7 @@ call_status(struct rpc_task *task) rpc_exit(task, status); break; default: - if (clnt->cl_chatty) - printk("%s: RPC call returned error %d\n", + printk("%s: RPC call returned error %d\n", clnt->cl_protname, -status); rpc_exit(task, status); } @@ -1175,8 +1157,7 @@ call_timeout(struct rpc_task *task) task->tk_timeouts++; if (RPC_IS_SOFT(task)) { - if (clnt->cl_chatty) - printk(KERN_NOTICE "%s: server %s not responding, timed out\n", + printk(KERN_NOTICE "%s: server %s not responding, timed out\n", clnt->cl_protname, clnt->cl_server); rpc_exit(task, -EIO); return; @@ -1184,8 +1165,7 @@ call_timeout(struct rpc_task *task) if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) { task->tk_flags |= RPC_CALL_MAJORSEEN; - if (clnt->cl_chatty) - printk(KERN_NOTICE "%s: server %s not responding, still trying\n", + printk(KERN_NOTICE "%s: server %s not responding, still trying\n", clnt->cl_protname, clnt->cl_server); } rpc_force_rebind(clnt); @@ -1216,9 +1196,8 @@ call_decode(struct rpc_task *task) task->tk_pid, task->tk_status); if (task->tk_flags & RPC_CALL_MAJORSEEN) { - if (clnt->cl_chatty) - printk(KERN_NOTICE "%s: server %s OK\n", - clnt->cl_protname, clnt->cl_server); + printk(KERN_NOTICE "%s: server %s OK\n", + clnt->cl_protname, clnt->cl_server); task->tk_flags &= ~RPC_CALL_MAJORSEEN; } @@ -1245,7 +1224,8 @@ call_decode(struct rpc_task *task) goto out_retry; } - p = rpc_verify_header(task); + /* Verify the RPC header */ + p = call_verify(task); if (IS_ERR(p)) { if (p == ERR_PTR(-EAGAIN)) goto out_retry; @@ -1263,7 +1243,7 @@ call_decode(struct rpc_task *task) return; out_retry: task->tk_status = 0; - /* Note: rpc_verify_header() may have freed the RPC slot */ + /* Note: call_verify() may have freed the RPC slot */ if (task->tk_rqstp == req) { req->rq_received = req->rq_rcv_buf.len = 0; if (task->tk_client->cl_discrtry) @@ -1310,8 +1290,11 @@ call_refreshresult(struct rpc_task *task) return; } +/* + * Call header serialization + */ static __be32 * -rpc_encode_header(struct rpc_task *task) +call_header(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; @@ -1331,8 +1314,11 @@ rpc_encode_header(struct rpc_task *task) return p; } +/* + * Reply header verification + */ static __be32 * -rpc_verify_header(struct rpc_task *task) +call_verify(struct rpc_task *task) { struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; int len = task->tk_rqstp->rq_rcv_buf.len >> 2; @@ -1406,7 +1392,7 @@ rpc_verify_header(struct rpc_task *task) task->tk_action = call_bind; goto out_retry; case RPC_AUTH_TOOWEAK: - printk(KERN_NOTICE "RPC: server %s requires stronger " + printk(KERN_NOTICE "call_verify: server %s requires stronger " "authentication.\n", task->tk_client->cl_server); break; default: @@ -1445,10 +1431,10 @@ rpc_verify_header(struct rpc_task *task) error = -EPROTONOSUPPORT; goto out_err; case RPC_PROC_UNAVAIL: - dprintk("RPC: %5u %s: proc %s unsupported by program %u, " + dprintk("RPC: %5u %s: proc %p unsupported by program %u, " "version %u on server %s\n", task->tk_pid, __func__, - rpc_proc_name(task), + task->tk_msg.rpc_proc, task->tk_client->cl_prog, task->tk_client->cl_vers, task->tk_client->cl_server); @@ -1531,53 +1517,44 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int EXPORT_SYMBOL_GPL(rpc_call_null); #ifdef RPC_DEBUG -static void rpc_show_header(void) -{ - printk(KERN_INFO "-pid- flgs status -client- --rqstp- " - "-timeout ---ops--\n"); -} - -static void rpc_show_task(const struct rpc_clnt *clnt, - const struct rpc_task *task) -{ - const char *rpc_waitq = "none"; - char *p, action[KSYM_SYMBOL_LEN]; - - if (RPC_IS_QUEUED(task)) - rpc_waitq = rpc_qname(task->tk_waitqueue); - - /* map tk_action pointer to a function name; then trim off - * the "+0x0 [sunrpc]" */ - sprint_symbol(action, (unsigned long)task->tk_action); - p = strchr(action, '+'); - if (p) - *p = '\0'; - - printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%s q:%s\n", - task->tk_pid, task->tk_flags, task->tk_status, - clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops, - clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task), - action, rpc_waitq); -} - void rpc_show_tasks(void) { struct rpc_clnt *clnt; - struct rpc_task *task; - int header = 0; + struct rpc_task *t; spin_lock(&rpc_client_lock); + if (list_empty(&all_clients)) + goto out; + printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " + "-rpcwait -action- ---ops--\n"); list_for_each_entry(clnt, &all_clients, cl_clients) { + if (list_empty(&clnt->cl_tasks)) + continue; spin_lock(&clnt->cl_lock); - list_for_each_entry(task, &clnt->cl_tasks, tk_task) { - if (!header) { - rpc_show_header(); - header++; - } - rpc_show_task(clnt, task); + list_for_each_entry(t, &clnt->cl_tasks, tk_task) { + const char *rpc_waitq = "none"; + int proc; + + if (t->tk_msg.rpc_proc) + proc = t->tk_msg.rpc_proc->p_proc; + else + proc = -1; + + if (RPC_IS_QUEUED(t)) + rpc_waitq = rpc_qname(t->tk_waitqueue); + + printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", + t->tk_pid, proc, + t->tk_flags, t->tk_status, + t->tk_client, + (t->tk_client ? t->tk_client->cl_prog : 0), + t->tk_rqstp, t->tk_timeout, + rpc_waitq, + t->tk_action, t->tk_ops); } spin_unlock(&clnt->cl_lock); } +out: spin_unlock(&rpc_client_lock); } #endif diff --git a/trunk/net/sunrpc/rpcb_clnt.c b/trunk/net/sunrpc/rpcb_clnt.c index 24db2b4d12d3..e6fb21b19b86 100644 --- a/trunk/net/sunrpc/rpcb_clnt.c +++ b/trunk/net/sunrpc/rpcb_clnt.c @@ -32,10 +32,6 @@ #define RPCBIND_PROGRAM (100000u) #define RPCBIND_PORT (111u) -#define RPCBVERS_2 (2u) -#define RPCBVERS_3 (3u) -#define RPCBVERS_4 (4u) - enum { RPCBPROC_NULL, RPCBPROC_SET, @@ -68,7 +64,6 @@ enum { #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) static void rpcb_getport_done(struct rpc_task *, void *); -static void rpcb_map_release(void *data); static struct rpc_program rpcb_program; struct rpcbind_args { @@ -81,73 +76,41 @@ struct rpcbind_args { const char * r_netid; const char * r_addr; const char * r_owner; - - int r_status; }; static struct rpc_procinfo rpcb_procedures2[]; static struct rpc_procinfo rpcb_procedures3[]; -static struct rpc_procinfo rpcb_procedures4[]; struct rpcb_info { - u32 rpc_vers; + int rpc_vers; struct rpc_procinfo * rpc_proc; }; static struct rpcb_info rpcb_next_version[]; static struct rpcb_info rpcb_next_version6[]; -static const struct rpc_call_ops rpcb_getport_ops = { - .rpc_call_done = rpcb_getport_done, - .rpc_release = rpcb_map_release, -}; - -static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) -{ - xprt_clear_binding(xprt); - rpc_wake_up_status(&xprt->binding, status); -} - static void rpcb_map_release(void *data) { struct rpcbind_args *map = data; - rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status); xprt_put(map->r_xprt); kfree(map); } -static const struct sockaddr_in rpcb_inaddr_loopback = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - .sin_port = htons(RPCBIND_PORT), -}; - -static const struct sockaddr_in6 rpcb_in6addr_loopback = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_LOOPBACK_INIT, - .sin6_port = htons(RPCBIND_PORT), +static const struct rpc_call_ops rpcb_getport_ops = { + .rpc_call_done = rpcb_getport_done, + .rpc_release = rpcb_map_release, }; -static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, - size_t addrlen, u32 version) +static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) { - struct rpc_create_args args = { - .protocol = XPRT_TRANSPORT_UDP, - .address = addr, - .addrsize = addrlen, - .servername = "localhost", - .program = &rpcb_program, - .version = version, - .authflavor = RPC_AUTH_UNIX, - .flags = RPC_CLNT_CREATE_NOPING, - }; - - return rpc_create(&args); + xprt_clear_binding(xprt); + rpc_wake_up_status(&xprt->binding, status); } static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, - size_t salen, int proto, u32 version) + size_t salen, int proto, u32 version, + int privileged) { struct rpc_create_args args = { .protocol = proto, @@ -157,8 +120,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, .program = &rpcb_program, .version = version, .authflavor = RPC_AUTH_UNIX, - .flags = (RPC_CLNT_CREATE_NOPING | - RPC_CLNT_CREATE_NONPRIVPORT), + .flags = RPC_CLNT_CREATE_NOPING, }; switch (srvaddr->sa_family) { @@ -172,72 +134,29 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, return NULL; } + if (!privileged) + args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; return rpc_create(&args); } -static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, - u32 version, struct rpc_message *msg, - int *result) -{ - struct rpc_clnt *rpcb_clnt; - int error = 0; - - *result = 0; - - rpcb_clnt = rpcb_create_local(addr, addrlen, version); - if (!IS_ERR(rpcb_clnt)) { - error = rpc_call_sync(rpcb_clnt, msg, 0); - rpc_shutdown_client(rpcb_clnt); - } else - error = PTR_ERR(rpcb_clnt); - - if (error < 0) - printk(KERN_WARNING "RPC: failed to contact local rpcbind " - "server (errno %d).\n", -error); - dprintk("RPC: registration status %d/%d\n", error, *result); - - return error; -} - /** * rpcb_register - set or unset a port registration with the local rpcbind svc * @prog: RPC program number to bind * @vers: RPC version number to bind - * @prot: transport protocol to register + * @prot: transport protocol to use to make this request * @port: port value to register - * @okay: OUT: result code - * - * RPC services invoke this function to advertise their contact - * information via the system's rpcbind daemon. RPC services - * invoke this function once for each [program, version, transport] - * tuple they wish to advertise. - * - * Callers may also unregister RPC services that are no longer - * available by setting the passed-in port to zero. This removes - * all registered transports for [program, version] from the local - * rpcbind database. - * - * Returns zero if the registration request was dispatched - * successfully and a reply was received. The rpcbind daemon's - * boolean result code is stored in *okay. - * - * Returns an errno value and sets *result to zero if there was - * some problem that prevented the rpcbind request from being - * dispatched, or if the rpcbind daemon did not respond within - * the timeout. + * @okay: result code * - * This function uses rpcbind protocol version 2 to contact the - * local rpcbind daemon. + * port == 0 means unregister, port != 0 means register. * - * Registration works over both AF_INET and AF_INET6, and services - * registered via this function are advertised as available for any - * address. If the local rpcbind daemon is listening on AF_INET6, - * services registered via this function will be advertised on - * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 - * addresses). + * This routine supports only rpcbind version 2. */ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) { + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; struct rpcbind_args map = { .r_prog = prog, .r_vers = vers, @@ -245,159 +164,32 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) .r_port = port, }; struct rpc_message msg = { + .rpc_proc = &rpcb_procedures2[port ? + RPCBPROC_SET : RPCBPROC_UNSET], .rpc_argp = &map, .rpc_resp = okay, }; + struct rpc_clnt *rpcb_clnt; + int error = 0; dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), prog, vers, prot, port); - msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; - if (port) - msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; - - return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, - sizeof(rpcb_inaddr_loopback), - RPCBVERS_2, &msg, okay); -} - -/* - * Fill in AF_INET family-specific arguments to register - */ -static int rpcb_register_netid4(struct sockaddr_in *address_to_register, - struct rpc_message *msg) -{ - struct rpcbind_args *map = msg->rpc_argp; - unsigned short port = ntohs(address_to_register->sin_port); - char buf[32]; - - /* Construct AF_INET universal address */ - snprintf(buf, sizeof(buf), - NIPQUAD_FMT".%u.%u", - NIPQUAD(address_to_register->sin_addr.s_addr), - port >> 8, port & 0xff); - map->r_addr = buf; - - dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " - "local rpcbind\n", (port ? "" : "un"), - map->r_prog, map->r_vers, - map->r_addr, map->r_netid); - - msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - if (port) - msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - - return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, - sizeof(rpcb_inaddr_loopback), - RPCBVERS_4, msg, msg->rpc_resp); -} - -/* - * Fill in AF_INET6 family-specific arguments to register - */ -static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, - struct rpc_message *msg) -{ - struct rpcbind_args *map = msg->rpc_argp; - unsigned short port = ntohs(address_to_register->sin6_port); - char buf[64]; - - /* Construct AF_INET6 universal address */ - snprintf(buf, sizeof(buf), - NIP6_FMT".%u.%u", - NIP6(address_to_register->sin6_addr), - port >> 8, port & 0xff); - map->r_addr = buf; - - dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " - "local rpcbind\n", (port ? "" : "un"), - map->r_prog, map->r_vers, - map->r_addr, map->r_netid); - - msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - if (port) - msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - - return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, - sizeof(rpcb_in6addr_loopback), - RPCBVERS_4, msg, msg->rpc_resp); -} - -/** - * rpcb_v4_register - set or unset a port registration with the local rpcbind - * @program: RPC program number of service to (un)register - * @version: RPC version number of service to (un)register - * @address: address family, IP address, and port to (un)register - * @netid: netid of transport protocol to (un)register - * @result: result code from rpcbind RPC call - * - * RPC services invoke this function to advertise their contact - * information via the system's rpcbind daemon. RPC services - * invoke this function once for each [program, version, address, - * netid] tuple they wish to advertise. - * - * Callers may also unregister RPC services that are no longer - * available by setting the port number in the passed-in address - * to zero. Callers pass a netid of "" to unregister all - * transport netids associated with [program, version, address]. - * - * Returns zero if the registration request was dispatched - * successfully and a reply was received. The rpcbind daemon's - * result code is stored in *result. - * - * Returns an errno value and sets *result to zero if there was - * some problem that prevented the rpcbind request from being - * dispatched, or if the rpcbind daemon did not respond within - * the timeout. - * - * This function uses rpcbind protocol version 4 to contact the - * local rpcbind daemon. The local rpcbind daemon must support - * version 4 of the rpcbind protocol in order for these functions - * to register a service successfully. - * - * Supported netids include "udp" and "tcp" for UDP and TCP over - * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6, - * respectively. - * - * The contents of @address determine the address family and the - * port to be registered. The usual practice is to pass INADDR_ANY - * as the raw address, but specifying a non-zero address is also - * supported by this API if the caller wishes to advertise an RPC - * service on a specific network interface. - * - * Note that passing in INADDR_ANY does not create the same service - * registration as IN6ADDR_ANY. The former advertises an RPC - * service on any IPv4 address, but not on IPv6. The latter - * advertises the service on all IPv4 and IPv6 addresses. - */ -int rpcb_v4_register(const u32 program, const u32 version, - const struct sockaddr *address, const char *netid, - int *result) -{ - struct rpcbind_args map = { - .r_prog = program, - .r_vers = version, - .r_netid = netid, - .r_owner = RPCB_OWNER_STRING, - }; - struct rpc_message msg = { - .rpc_argp = &map, - .rpc_resp = result, - }; + rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, + sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1); + if (IS_ERR(rpcb_clnt)) + return PTR_ERR(rpcb_clnt); - *result = 0; + error = rpc_call_sync(rpcb_clnt, &msg, 0); - switch (address->sa_family) { - case AF_INET: - return rpcb_register_netid4((struct sockaddr_in *)address, - &msg); - case AF_INET6: - return rpcb_register_netid6((struct sockaddr_in6 *)address, - &msg); - } + rpc_shutdown_client(rpcb_clnt); + if (error < 0) + printk(KERN_WARNING "RPC: failed to contact local rpcbind " + "server (errno %d).\n", -error); + dprintk("RPC: registration status %d/%d\n", error, *okay); - return -EAFNOSUPPORT; + return error; } /** @@ -435,7 +227,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, - sizeof(*sin), prot, RPCBVERS_2); + sizeof(*sin), prot, 2, 0); if (IS_ERR(rpcb_clnt)) return PTR_ERR(rpcb_clnt); @@ -497,16 +289,17 @@ void rpcb_getport_async(struct rpc_task *task) /* Autobind on cloned rpc clients is discouraged */ BUG_ON(clnt->cl_parent != clnt); - /* Put self on the wait queue to ensure we get notified if - * some other task is already attempting to bind the port */ - rpc_sleep_on(&xprt->binding, task, NULL); - if (xprt_test_and_set_binding(xprt)) { + status = -EAGAIN; /* tell caller to check again */ dprintk("RPC: %5u %s: waiting for another binder\n", task->tk_pid, __func__); - return; + goto bailout_nowake; } + /* Put self on queue before sending rpcbind request, in case + * rpcb_getport_done completes before we return from rpc_run_task */ + rpc_sleep_on(&xprt->binding, task, NULL); + /* Someone else may have bound if we slept */ if (xprt_bound(xprt)) { status = 0; @@ -545,7 +338,7 @@ void rpcb_getport_async(struct rpc_task *task) task->tk_pid, __func__, bind_version); rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, - bind_version); + bind_version, 0); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", @@ -568,15 +361,15 @@ void rpcb_getport_async(struct rpc_task *task) map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ - map->r_status = -EIO; child = rpcb_call_async(rpcb_clnt, map, proc); rpc_release_client(rpcb_clnt); if (IS_ERR(child)) { + status = -EIO; /* rpcb_map_release() has freed the arguments */ dprintk("RPC: %5u %s: rpc_run_task failed\n", task->tk_pid, __func__); - return; + goto bailout_nofree; } rpc_put_task(child); @@ -585,6 +378,7 @@ void rpcb_getport_async(struct rpc_task *task) bailout_nofree: rpcb_wake_rpcbind_waiters(xprt, status); +bailout_nowake: task->tk_status = status; } EXPORT_SYMBOL_GPL(rpcb_getport_async); @@ -623,13 +417,9 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", child->tk_pid, status, map->r_port); - map->r_status = status; + rpcb_wake_rpcbind_waiters(xprt, status); } -/* - * XDR functions for rpcbind - */ - static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { @@ -648,7 +438,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, unsigned short *portp) { *portp = (unsigned short) ntohl(*p++); - dprintk("RPC: rpcb_decode_getport result %u\n", + dprintk("RPC: rpcb_decode_getport result %u\n", *portp); return 0; } @@ -657,8 +447,8 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, unsigned int *boolp) { *boolp = (unsigned int) ntohl(*p++); - dprintk("RPC: rpcb_decode_set: call %s\n", - (*boolp ? "succeeded" : "failed")); + dprintk("RPC: rpcb_decode_set result %u\n", + *boolp); return 0; } @@ -781,60 +571,52 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, static struct rpc_procinfo rpcb_procedures2[] = { PROC(SET, mapping, set), PROC(UNSET, mapping, set), - PROC(GETPORT, mapping, getport), + PROC(GETADDR, mapping, getport), }; static struct rpc_procinfo rpcb_procedures3[] = { - PROC(SET, getaddr, set), - PROC(UNSET, getaddr, set), + PROC(SET, mapping, set), + PROC(UNSET, mapping, set), PROC(GETADDR, getaddr, getaddr), }; static struct rpc_procinfo rpcb_procedures4[] = { - PROC(SET, getaddr, set), - PROC(UNSET, getaddr, set), - PROC(GETADDR, getaddr, getaddr), + PROC(SET, mapping, set), + PROC(UNSET, mapping, set), PROC(GETVERSADDR, getaddr, getaddr), }; static struct rpcb_info rpcb_next_version[] = { - { - .rpc_vers = RPCBVERS_2, - .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], - }, - { - .rpc_proc = NULL, - }, +#ifdef CONFIG_SUNRPC_BIND34 + { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] }, + { 3, &rpcb_procedures3[RPCBPROC_GETADDR] }, +#endif + { 2, &rpcb_procedures2[RPCBPROC_GETPORT] }, + { 0, NULL }, }; static struct rpcb_info rpcb_next_version6[] = { - { - .rpc_vers = RPCBVERS_4, - .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], - }, - { - .rpc_vers = RPCBVERS_3, - .rpc_proc = &rpcb_procedures3[RPCBPROC_GETADDR], - }, - { - .rpc_proc = NULL, - }, +#ifdef CONFIG_SUNRPC_BIND34 + { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] }, + { 3, &rpcb_procedures3[RPCBPROC_GETADDR] }, +#endif + { 0, NULL }, }; static struct rpc_version rpcb_version2 = { - .number = RPCBVERS_2, + .number = 2, .nrprocs = RPCB_HIGHPROC_2, .procs = rpcb_procedures2 }; static struct rpc_version rpcb_version3 = { - .number = RPCBVERS_3, + .number = 3, .nrprocs = RPCB_HIGHPROC_3, .procs = rpcb_procedures3 }; static struct rpc_version rpcb_version4 = { - .number = RPCBVERS_4, + .number = 4, .nrprocs = RPCB_HIGHPROC_4, .procs = rpcb_procedures4 }; diff --git a/trunk/net/sunrpc/sched.c b/trunk/net/sunrpc/sched.c index 385f427bedad..6eab9bf94baf 100644 --- a/trunk/net/sunrpc/sched.c +++ b/trunk/net/sunrpc/sched.c @@ -576,7 +576,9 @@ EXPORT_SYMBOL_GPL(rpc_delay); */ static void rpc_prepare_task(struct rpc_task *task) { + lock_kernel(); task->tk_ops->rpc_call_prepare(task, task->tk_calldata); + unlock_kernel(); } /* @@ -586,7 +588,9 @@ void rpc_exit_task(struct rpc_task *task) { task->tk_action = NULL; if (task->tk_ops->rpc_call_done != NULL) { + lock_kernel(); task->tk_ops->rpc_call_done(task, task->tk_calldata); + unlock_kernel(); if (task->tk_action != NULL) { WARN_ON(RPC_ASSASSINATED(task)); /* Always release the RPC slot and buffer memory */ @@ -598,8 +602,11 @@ EXPORT_SYMBOL_GPL(rpc_exit_task); void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) { - if (ops->rpc_release != NULL) + if (ops->rpc_release != NULL) { + lock_kernel(); ops->rpc_release(calldata); + unlock_kernel(); + } } /* @@ -619,15 +626,19 @@ static void __rpc_execute(struct rpc_task *task) /* * Execute any pending callback. */ - if (task->tk_callback) { + if (RPC_DO_CALLBACK(task)) { + /* Define a callback save pointer */ void (*save_callback)(struct rpc_task *); /* - * We set tk_callback to NULL before calling it, - * in case it sets the tk_callback field itself: + * If a callback exists, save it, reset it, + * call it. + * The save is needed to stop from resetting + * another callback set within the callback handler + * - Dave */ - save_callback = task->tk_callback; - task->tk_callback = NULL; + save_callback=task->tk_callback; + task->tk_callback=NULL; save_callback(task); } diff --git a/trunk/net/sunrpc/xprt.c b/trunk/net/sunrpc/xprt.c index 99a52aabe332..e1770f7ba0b3 100644 --- a/trunk/net/sunrpc/xprt.c +++ b/trunk/net/sunrpc/xprt.c @@ -690,7 +690,7 @@ static void xprt_connect_status(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - if (task->tk_status == 0) { + if (task->tk_status >= 0) { xprt->stat.connect_count++; xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; dprintk("RPC: %5u xprt_connect_status: connection established\n", @@ -699,6 +699,12 @@ static void xprt_connect_status(struct rpc_task *task) } switch (task->tk_status) { + case -ECONNREFUSED: + case -ECONNRESET: + dprintk("RPC: %5u xprt_connect_status: server %s refused " + "connection\n", task->tk_pid, + task->tk_client->cl_server); + break; case -ENOTCONN: dprintk("RPC: %5u xprt_connect_status: connection broken\n", task->tk_pid); @@ -872,7 +878,6 @@ void xprt_transmit(struct rpc_task *task) return; req->rq_connect_cookie = xprt->connect_cookie; - req->rq_xtime = jiffies; status = xprt->ops->send_request(task); if (status == 0) { dprintk("RPC: %5u xmit complete\n", task->tk_pid); diff --git a/trunk/net/sunrpc/xprtsock.c b/trunk/net/sunrpc/xprtsock.c index 4486c59c3aca..ddbe981ab516 100644 --- a/trunk/net/sunrpc/xprtsock.c +++ b/trunk/net/sunrpc/xprtsock.c @@ -579,6 +579,7 @@ static int xs_udp_send_request(struct rpc_task *task) req->rq_svec->iov_base, req->rq_svec->iov_len); + req->rq_xtime = jiffies; status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen, xdr, @@ -670,6 +671,7 @@ static int xs_tcp_send_request(struct rpc_task *task) * to cope with writespace callbacks arriving _after_ we have * called sendmsg(). */ while (1) { + req->rq_xtime = jiffies; status = xs_sendpages(transport->sock, NULL, 0, xdr, req->rq_bytes_sent);