From 0ee5c6d632324a4b278cb0b29eb8effce4c8a358 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 2 Aug 2012 15:46:30 -0400 Subject: vfs: don't treat fl_type as a bitmap The rules for fl_type are rather convoluted. Typically it's treated as holding specific values, except in the case of LOCK_MAND, in which case it can be or'ed with LOCK_READ|LOCK_WRITE. On some arches F_WRLCK == 2 and F_UNLCK == 3, so and'ing with F_WRLCK will also catch the F_UNLCK case. It's unlikely in either case here that we'd ever see F_UNLCK since those shouldn't end up on any lists, but it's still best to be consistent. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/locks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 7e81bfc75164..669911e4af9d 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(__break_lease); void lease_get_mtime(struct inode *inode, struct timespec *time) { struct file_lock *flock = inode->i_flock; - if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK)) + if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK)) *time = current_fs_time(inode->i_sb); else *time = inode->i_mtime; @@ -2187,8 +2187,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, } else { seq_printf(f, "%s ", (lease_breaking(fl)) - ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " - : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); + ? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ " + : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); } if (inode) { #ifdef WE_CAN_BREAK_LSLK_NOW -- cgit v1.2.2 From 1696c47ce2f42e671f6a17682b533273f4ac7963 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 6 Aug 2012 11:00:27 -0400 Subject: nfsd: trivial comment updates locks.c doesn't use the BKL anymore and there is no fi_perfile field. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 5 ----- fs/nfsd/state.h | 6 +----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cc894eda385a..566a9b75fa0e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4151,11 +4151,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); nfs4_transform_lock_offset(&file_lock); - /* - * Try to lock the file in the VFS. - * Note: locks.c uses the BKL to protect the inode's lock list. - */ - err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); switch (-err) { case 0: /* success! */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 22bd0a66c356..ec513fd4bae9 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -373,11 +373,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) return container_of(so, struct nfs4_lockowner, lo_owner); } -/* -* nfs4_file: a file opened by some number of (open) nfs4_stateowners. -* o fi_perfile list is used to search for conflicting -* share_acces, share_deny on the file. -*/ +/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */ struct nfs4_file { atomic_t fi_ref; struct list_head fi_hash; /* hash by "struct inode *" */ -- cgit v1.2.2 From 9c0b0ff79935c7e18b2f2f0d66de7086f57c077b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 14:16:05 -0400 Subject: nfsd4: nfsaclsvc_encode_voidres static Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 6aa5590c3679..b314888825d5 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -218,8 +218,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, * There must be an encoding function for void results so svc_process * will work properly. */ -int -nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) +static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } -- cgit v1.2.2 From 87f26f9b087643d2e28a5dfbec2e03ac09422fc4 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 15:49:26 -0400 Subject: nfsd4: declare nfs4_recoverydir properly Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsctl.c | 2 -- fs/nfsd/nfsd.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index fa49cff5ee65..009632a68f31 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1008,8 +1008,6 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size) return nfsd4_write_time(file, buf, size, &nfsd4_grace); } -extern char *nfs4_recoverydir(void); - static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) { char *mesg = buf; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 2244222368ab..36243a33f193 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -124,6 +124,7 @@ int nfs4_state_start(void); void nfs4_state_shutdown(void); void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); +char * nfs4_recoverydir(void); #else static inline void nfs4_state_init(void) { } static inline int nfsd4_init_slabs(void) { return 0; } @@ -132,6 +133,7 @@ static inline int nfs4_state_start(void) { return 0; } static inline void nfs4_state_shutdown(void) { } static inline void nfs4_reset_lease(time_t leasetime) { } static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } +static inline char * nfs4_recoverydir(void) {return NULL; } #endif /* -- cgit v1.2.2 From 95c7a20aeb3a6425673b673417b29f427739f7e7 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 15:50:11 -0400 Subject: nfsd: do_nfsd_create verf argument is a u32 The types here are actually a bit of a mess. For now cast as we do in the v4 case. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs3proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 9095f3c21df9..97d90d1c8608 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -247,7 +247,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* Now create the file and set attributes */ nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, attr, newfhp, - argp->createmode, argp->verf, NULL, NULL); + argp->createmode, (u32 *)argp->verf, NULL, NULL); RETURN_STATUS(nfserr); } -- cgit v1.2.2 From 24ff99c6fe0f071994262e39fa334f28606d2cad Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 14 Aug 2012 15:55:08 -0400 Subject: NFSD: Swap the struct nfs4_operation getter and setter stateid_setter should be matched to op_set_currentstateid, rather than op_get_currentstateid. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c9c1c0a25417..f2bb0ef67b2a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1054,8 +1054,8 @@ struct nfsd4_operation { char *op_name; /* Try to get response size before operation */ nfsd4op_rsize op_rsize_bop; - stateid_setter op_get_currentstateid; - stateid_getter op_set_currentstateid; + stateid_getter op_get_currentstateid; + stateid_setter op_set_currentstateid; }; static struct nfsd4_operation nfsd4_ops[]; -- cgit v1.2.2 From da5c80a935d422bcc8a69b362f5d1b47ef94d3de Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Aug 2012 16:09:31 -0400 Subject: nfsd4: nfsd_process_n_delegations should be static Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 566a9b75fa0e..f393da8c26e1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4578,7 +4578,7 @@ void nfsd_forget_openowners(u64 num) printk(KERN_INFO "NFSD: Forgot %d open owners", count); } -int nfsd_process_n_delegations(u64 num, struct list_head *list) +static int nfsd_process_n_delegations(u64 num, struct list_head *list) { int i, count = 0; struct nfs4_file *fp, *fnext; -- cgit v1.2.2 From 5592a3f3978c57175ef817a4f773bc0d6d8949b9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 21 Aug 2012 08:02:31 -0400 Subject: knfsd: remove bogus BUG_ON() call from nfsd4_locku The code checks for a NULL filp and handles it gracefully just before this BUG_ON. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f393da8c26e1..123b47105c0d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4294,7 +4294,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_lock_range; goto out; } - BUG_ON(!filp); locks_init_lock(&file_lock); file_lock.fl_type = F_UNLCK; file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); -- cgit v1.2.2 From 21179d81f1de37c93435dce10d2a4378c370ecca Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 21 Aug 2012 08:03:32 -0400 Subject: knfsd: don't allocate file_locks on the stack struct file_lock is pretty large and really ought not live on the stack. On my x86_64 machine, they're almost 200 bytes each. (gdb) p sizeof(struct file_lock) $1 = 192 ...allocate them dynamically instead. Reported-by: Al Viro Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 118 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 123b47105c0d..5f1a91a9cd35 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4046,8 +4046,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_lockowner *lock_sop = NULL; struct nfs4_ol_stateid *lock_stp; struct file *filp = NULL; - struct file_lock file_lock; - struct file_lock conflock; + struct file_lock *file_lock = NULL; + struct file_lock *conflock = NULL; __be32 status = 0; bool new_state = false; int lkflg; @@ -4117,21 +4117,28 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) goto out; - locks_init_lock(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + + locks_init_lock(file_lock); switch (lock->lk_type) { case NFS4_READ_LT: case NFS4_READW_LT: filp = find_readable_file(lock_stp->st_file); if (filp) get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); - file_lock.fl_type = F_RDLCK; + file_lock->fl_type = F_RDLCK; break; case NFS4_WRITE_LT: case NFS4_WRITEW_LT: filp = find_writeable_file(lock_stp->st_file); if (filp) get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); - file_lock.fl_type = F_WRLCK; + file_lock->fl_type = F_WRLCK; break; default: status = nfserr_inval; @@ -4141,17 +4148,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_openmode; goto out; } - file_lock.fl_owner = (fl_owner_t)lock_sop; - file_lock.fl_pid = current->tgid; - file_lock.fl_file = filp; - file_lock.fl_flags = FL_POSIX; - file_lock.fl_lmops = &nfsd_posix_mng_ops; - - file_lock.fl_start = lock->lk_offset; - file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); - nfs4_transform_lock_offset(&file_lock); + file_lock->fl_owner = (fl_owner_t)lock_sop; + file_lock->fl_pid = current->tgid; + file_lock->fl_file = filp; + file_lock->fl_flags = FL_POSIX; + file_lock->fl_lmops = &nfsd_posix_mng_ops; + file_lock->fl_start = lock->lk_offset; + file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); + nfs4_transform_lock_offset(file_lock); + + conflock = locks_alloc_lock(); + if (!conflock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } - err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); + err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); switch (-err) { case 0: /* success! */ update_stateid(&lock_stp->st_stid.sc_stateid); @@ -4162,7 +4175,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, case (EAGAIN): /* conflock holds conflicting lock */ status = nfserr_denied; dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); - nfs4_set_lock_denied(&conflock, &lock->lk_denied); + nfs4_set_lock_denied(conflock, &lock->lk_denied); break; case (EDEADLK): status = nfserr_deadlock; @@ -4177,6 +4190,10 @@ out: release_lockowner(lock_sop); if (!cstate->replay_owner) nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); + if (conflock) + locks_free_lock(conflock); return status; } @@ -4205,7 +4222,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_lockt *lockt) { struct inode *inode; - struct file_lock file_lock; + struct file_lock *file_lock = NULL; struct nfs4_lockowner *lo; __be32 status; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -4226,15 +4243,21 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; inode = cstate->current_fh.fh_dentry->d_inode; - locks_init_lock(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + locks_init_lock(file_lock); switch (lockt->lt_type) { case NFS4_READ_LT: case NFS4_READW_LT: - file_lock.fl_type = F_RDLCK; + file_lock->fl_type = F_RDLCK; break; case NFS4_WRITE_LT: case NFS4_WRITEW_LT: - file_lock.fl_type = F_WRLCK; + file_lock->fl_type = F_WRLCK; break; default: dprintk("NFSD: nfs4_lockt: bad lock type!\n"); @@ -4244,25 +4267,27 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); if (lo) - file_lock.fl_owner = (fl_owner_t)lo; - file_lock.fl_pid = current->tgid; - file_lock.fl_flags = FL_POSIX; + file_lock->fl_owner = (fl_owner_t)lo; + file_lock->fl_pid = current->tgid; + file_lock->fl_flags = FL_POSIX; - file_lock.fl_start = lockt->lt_offset; - file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); + file_lock->fl_start = lockt->lt_offset; + file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); - nfs4_transform_lock_offset(&file_lock); + nfs4_transform_lock_offset(file_lock); - status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); + status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); if (status) goto out; - if (file_lock.fl_type != F_UNLCK) { + if (file_lock->fl_type != F_UNLCK) { status = nfserr_denied; - nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); + nfs4_set_lock_denied(file_lock, &lockt->lt_denied); } out: nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); return status; } @@ -4272,7 +4297,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfs4_ol_stateid *stp; struct file *filp = NULL; - struct file_lock file_lock; + struct file_lock *file_lock = NULL; __be32 status; int err; @@ -4294,22 +4319,29 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_lock_range; goto out; } - locks_init_lock(&file_lock); - file_lock.fl_type = F_UNLCK; - file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); - file_lock.fl_pid = current->tgid; - file_lock.fl_file = filp; - file_lock.fl_flags = FL_POSIX; - file_lock.fl_lmops = &nfsd_posix_mng_ops; - file_lock.fl_start = locku->lu_offset; - - file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); - nfs4_transform_lock_offset(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + locks_init_lock(file_lock); + file_lock->fl_type = F_UNLCK; + file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); + file_lock->fl_pid = current->tgid; + file_lock->fl_file = filp; + file_lock->fl_flags = FL_POSIX; + file_lock->fl_lmops = &nfsd_posix_mng_ops; + file_lock->fl_start = locku->lu_offset; + + file_lock->fl_end = last_byte_offset(locku->lu_offset, + locku->lu_length); + nfs4_transform_lock_offset(file_lock); /* * Try to unlock the file in the VFS. */ - err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); + err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); if (err) { dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); goto out_nfserr; @@ -4323,6 +4355,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, out: if (!cstate->replay_owner) nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); return status; out_nfserr: -- cgit v1.2.2 From 719f8bcc883e7992615f4d5625922e24995e2d98 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 13 Aug 2012 17:03:00 -0400 Subject: svcrpc: fix xpt_list traversal locking on shutdown Server threads are not running at this point, but svc_age_temp_xprts still may be, so we need this locking. Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index bac973a31367..e1810b947dea 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -917,16 +917,18 @@ void svc_close_xprt(struct svc_xprt *xprt) } EXPORT_SYMBOL_GPL(svc_close_xprt); -static void svc_close_list(struct list_head *xprt_list, struct net *net) +static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; + spin_lock(&serv->sv_lock); list_for_each_entry(xprt, xprt_list, xpt_list) { if (xprt->xpt_net != net) continue; set_bit(XPT_CLOSE, &xprt->xpt_flags); set_bit(XPT_BUSY, &xprt->xpt_flags); } + spin_unlock(&serv->sv_lock); } static void svc_clear_pools(struct svc_serv *serv, struct net *net) @@ -949,24 +951,28 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net) } } -static void svc_clear_list(struct list_head *xprt_list, struct net *net) +static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; struct svc_xprt *tmp; + LIST_HEAD(victims); + spin_lock(&serv->sv_lock); list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { if (xprt->xpt_net != net) continue; - svc_delete_xprt(xprt); + list_move(&xprt->xpt_list, &victims); } - list_for_each_entry(xprt, xprt_list, xpt_list) - BUG_ON(xprt->xpt_net == net); + spin_unlock(&serv->sv_lock); + + list_for_each_entry_safe(xprt, tmp, &victims, xpt_list) + svc_delete_xprt(xprt); } void svc_close_net(struct svc_serv *serv, struct net *net) { - svc_close_list(&serv->sv_tempsocks, net); - svc_close_list(&serv->sv_permsocks, net); + svc_close_list(serv, &serv->sv_tempsocks, net); + svc_close_list(serv, &serv->sv_permsocks, net); svc_clear_pools(serv, net); /* @@ -974,8 +980,8 @@ void svc_close_net(struct svc_serv *serv, struct net *net) * svc_xprt_enqueue will not add new entries without taking the * sp_lock and checking XPT_BUSY. */ - svc_clear_list(&serv->sv_tempsocks, net); - svc_clear_list(&serv->sv_permsocks, net); + svc_clear_list(serv, &serv->sv_tempsocks, net); + svc_clear_list(serv, &serv->sv_permsocks, net); } /* -- cgit v1.2.2 From 72c3537607e42928f13691d59579ec840014b19e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 13 Aug 2012 17:46:17 -0400 Subject: svcrpc: standardize svc_setup_socket return convention Use the kernel-standard ptr-or-error return convention instead of passing a pointer to the error. Signed-off-by: J. Bruce Fields --- net/sunrpc/svcsock.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 998aa8c1807c..d028b51a69ad 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -59,7 +59,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, - int *errp, int flags); + int flags); static void svc_udp_data_ready(struct sock *, int); static int svc_udp_recvfrom(struct svc_rqst *); static int svc_udp_sendto(struct svc_rqst *); @@ -900,8 +900,9 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt) */ newsock->sk->sk_sndtimeo = HZ*30; - if (!(newsvsk = svc_setup_socket(serv, newsock, &err, - (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY)))) + newsvsk = svc_setup_socket(serv, newsock, + (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY)); + if (IS_ERR(newsvsk)) goto failed; svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen); err = kernel_getsockname(newsock, sin, &slen); @@ -1383,29 +1384,29 @@ EXPORT_SYMBOL_GPL(svc_sock_update_bufs); */ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, struct socket *sock, - int *errp, int flags) + int flags) { struct svc_sock *svsk; struct sock *inet; int pmap_register = !(flags & SVC_SOCK_ANONYMOUS); + int err = 0; dprintk("svc: svc_setup_socket %p\n", sock); - if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) { - *errp = -ENOMEM; - return NULL; - } + svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); + if (!svsk) + return ERR_PTR(-ENOMEM); inet = sock->sk; /* Register socket with portmapper */ - if (*errp >= 0 && pmap_register) - *errp = svc_register(serv, sock_net(sock->sk), inet->sk_family, + if (pmap_register) + err = svc_register(serv, sock_net(sock->sk), inet->sk_family, inet->sk_protocol, ntohs(inet_sk(inet)->inet_sport)); - if (*errp < 0) { + if (err < 0) { kfree(svsk); - return NULL; + return ERR_PTR(err); } inet->sk_user_data = svsk; @@ -1463,10 +1464,12 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, else { if (!try_module_get(THIS_MODULE)) err = -ENOENT; - else - svsk = svc_setup_socket(serv, so, &err, - SVC_SOCK_DEFAULTS); - if (svsk) { + else { + svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS); + if (IS_ERR(svsk)) + err = PTR_ERR(svsk); + } + if (err == 0) { struct sockaddr_storage addr; struct sockaddr *sin = (struct sockaddr *)&addr; int salen; @@ -1563,11 +1566,12 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, goto bummer; } - if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) { + svsk = svc_setup_socket(serv, sock, flags); + if (!IS_ERR(svsk)) { svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); return (struct svc_xprt *)svsk; } - + error = PTR_ERR(svsk); bummer: dprintk("svc: svc_create_socket error = %d\n", -error); sock_release(sock); -- cgit v1.2.2 From a8e10078a87c8a2c3c8d0f9856c0f74272fc0f74 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 13 Aug 2012 18:01:03 -0400 Subject: svcrpc: clean up control flow Mainly, use the kernel standard err = -ERROR; if (something_bad) goto out; normal case; rather than if (something_bad) err = -ERROR else { normal case; } Signed-off-by: J. Bruce Fields --- net/sunrpc/svcsock.c | 69 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index d028b51a69ad..bf10b723f429 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1451,44 +1451,42 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, int err = 0; struct socket *so = sockfd_lookup(fd, &err); struct svc_sock *svsk = NULL; + struct sockaddr_storage addr; + struct sockaddr *sin = (struct sockaddr *)&addr; + int salen; if (!so) return err; + err = -EAFNOSUPPORT; if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6)) - err = -EAFNOSUPPORT; - else if (so->sk->sk_protocol != IPPROTO_TCP && + goto out; + err = -EPROTONOSUPPORT; + if (so->sk->sk_protocol != IPPROTO_TCP && so->sk->sk_protocol != IPPROTO_UDP) - err = -EPROTONOSUPPORT; - else if (so->state > SS_UNCONNECTED) - err = -EISCONN; - else { - if (!try_module_get(THIS_MODULE)) - err = -ENOENT; - else { - svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS); - if (IS_ERR(svsk)) - err = PTR_ERR(svsk); - } - if (err == 0) { - struct sockaddr_storage addr; - struct sockaddr *sin = (struct sockaddr *)&addr; - int salen; - if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0) - svc_xprt_set_local(&svsk->sk_xprt, sin, salen); - clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags); - spin_lock_bh(&serv->sv_lock); - list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks); - spin_unlock_bh(&serv->sv_lock); - svc_xprt_received(&svsk->sk_xprt); - err = 0; - } else - module_put(THIS_MODULE); - } - if (err) { - sockfd_put(so); - return err; + goto out; + err = -EISCONN; + if (so->state > SS_UNCONNECTED) + goto out; + err = -ENOENT; + if (!try_module_get(THIS_MODULE)) + goto out; + svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS); + if (IS_ERR(svsk)) { + module_put(THIS_MODULE); + err = PTR_ERR(svsk); + goto out; } + if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0) + svc_xprt_set_local(&svsk->sk_xprt, sin, salen); + clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags); + spin_lock_bh(&serv->sv_lock); + list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks); + spin_unlock_bh(&serv->sv_lock); + svc_xprt_received(&svsk->sk_xprt); return svc_one_sock_name(svsk, name_return, len); +out: + sockfd_put(so); + return err; } EXPORT_SYMBOL_GPL(svc_addsock); @@ -1567,11 +1565,12 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, } svsk = svc_setup_socket(serv, sock, flags); - if (!IS_ERR(svsk)) { - svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); - return (struct svc_xprt *)svsk; + if (IS_ERR(svsk)) { + error = PTR_ERR(svsk); + goto bummer; } - error = PTR_ERR(svsk); + svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); + return (struct svc_xprt *)svsk; bummer: dprintk("svc: svc_create_socket error = %d\n", -error); sock_release(sock); -- cgit v1.2.2 From c3341966943284ab3618a1814cefd693ad9aa736 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Aug 2012 15:27:23 -0400 Subject: svcrpc: make svc_create_xprt enqueue on clearing XPT_BUSY Whenever we clear XPT_BUSY we should call svc_xprt_enqueue(). Without that we may fail to notice any events (such as new connections) that arrived while XPT_BUSY was set. Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index e1810b947dea..4801fdac2c9d 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -238,7 +238,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, list_add(&newxprt->xpt_list, &serv->sv_permsocks); spin_unlock_bh(&serv->sv_lock); newport = svc_xprt_local_port(newxprt); - clear_bit(XPT_BUSY, &newxprt->xpt_flags); + svc_xprt_received(newxprt); return newport; } err: -- cgit v1.2.2 From 39b553013719fe6495cf5e496b827b2d712e4265 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Aug 2012 15:50:34 -0400 Subject: svcrpc: share some setup of listening sockets There's some duplicate code here. Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_xprt.h | 1 + net/sunrpc/svc_xprt.c | 16 ++++++++++------ net/sunrpc/svcsock.c | 6 +----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index b3f64b12f141..73c7a68667ea 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -124,6 +124,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, struct net *net, const sa_family_t af, const unsigned short port); int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); +void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); static inline void svc_xprt_get(struct svc_xprt *xprt) { diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 4801fdac2c9d..ee15663798b3 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -208,6 +208,15 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); } +void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) +{ + clear_bit(XPT_TEMP, &new->xpt_flags); + spin_lock_bh(&serv->sv_lock); + list_add(&new->xpt_list, &serv->sv_permsocks); + spin_unlock_bh(&serv->sv_lock); + svc_xprt_received(new); +} + int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags) @@ -232,13 +241,8 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, module_put(xcl->xcl_owner); return PTR_ERR(newxprt); } - - clear_bit(XPT_TEMP, &newxprt->xpt_flags); - spin_lock_bh(&serv->sv_lock); - list_add(&newxprt->xpt_list, &serv->sv_permsocks); - spin_unlock_bh(&serv->sv_lock); + svc_add_new_perm_xprt(serv, newxprt); newport = svc_xprt_local_port(newxprt); - svc_xprt_received(newxprt); return newport; } err: diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index bf10b723f429..c7a7b14f54ed 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1478,11 +1478,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, } if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0) svc_xprt_set_local(&svsk->sk_xprt, sin, salen); - clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags); - spin_lock_bh(&serv->sv_lock); - list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks); - spin_unlock_bh(&serv->sv_lock); - svc_xprt_received(&svsk->sk_xprt); + svc_add_new_perm_xprt(serv, &svsk->sk_xprt); return svc_one_sock_name(svsk, name_return, len); out: sockfd_put(so); -- cgit v1.2.2 From 38af2cabb6285e1c44d2cc3165f150d2aa5f38a8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Aug 2012 16:16:34 -0400 Subject: nfsd: remove redundant "port" argument "port" in all these functions is always NFS_PORT. nfsd can already be run on a nonstandard port using the "nfsd/portlist" interface. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsctl.c | 2 +- fs/nfsd/nfsd.h | 2 +- fs/nfsd/nfssvc.c | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 009632a68f31..89be13c9e769 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -406,7 +406,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) return rv; if (newthreads < 0) return -EINVAL; - rv = nfsd_svc(NFS_PORT, newthreads); + rv = nfsd_svc(newthreads); if (rv < 0) return rv; } else diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 36243a33f193..80d5ce40aadb 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op; /* * Function prototypes. */ -int nfsd_svc(unsigned short port, int nrservs); +int nfsd_svc(int nrservs); int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); int nfsd_nrthreads(void); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 240473cb708f..dd2b7343d741 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -183,18 +183,18 @@ int nfsd_nrthreads(void) return rv; } -static int nfsd_init_socks(int port) +static int nfsd_init_socks(void) { int error; if (!list_empty(&nfsd_serv->sv_permsocks)) return 0; - error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port, + error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; - error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port, + error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; @@ -204,7 +204,7 @@ static int nfsd_init_socks(int port) static bool nfsd_up = false; -static int nfsd_startup(unsigned short port, int nrservs) +static int nfsd_startup(int nrservs) { int ret; @@ -218,7 +218,7 @@ static int nfsd_startup(unsigned short port, int nrservs) ret = nfsd_racache_init(2*nrservs); if (ret) return ret; - ret = nfsd_init_socks(port); + ret = nfsd_init_socks(); if (ret) goto out_racache; ret = lockd_up(&init_net); @@ -436,7 +436,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) * this is the first time nrservs is nonzero. */ int -nfsd_svc(unsigned short port, int nrservs) +nfsd_svc(int nrservs) { int error; bool nfsd_up_before; @@ -458,7 +458,7 @@ nfsd_svc(unsigned short port, int nrservs) nfsd_up_before = nfsd_up; - error = nfsd_startup(port, nrservs); + error = nfsd_startup(nrservs); if (error) goto out_destroy; error = svc_set_num_threads(nfsd_serv, NULL, nrservs); -- cgit v1.2.2 From a10fded18eb275e7e97e57e7542b16c665fe61ec Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Aug 2012 17:48:39 -0400 Subject: nfsd: allow configuring nfsd to listen on 5-digit ports Note a 16-bit value can require up to 5 digits. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 89be13c9e769..e41a08ffbe0a 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -712,7 +712,7 @@ static ssize_t __write_ports_addxprt(char *buf) int port, err; struct net *net = &init_net; - if (sscanf(buf, "%15s %4u", transport, &port) != 2) + if (sscanf(buf, "%15s %5u", transport, &port) != 2) return -EINVAL; if (port < 1 || port > USHRT_MAX) -- cgit v1.2.2 From f23abfdb94fda3108441530cb4a813088d3f9176 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Aug 2012 20:32:27 -0400 Subject: svcrpc: minor udp code cleanup Order the code in a more boring way. Signed-off-by: J. Bruce Fields --- net/sunrpc/svcsock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index c7a7b14f54ed..06ae8a755349 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -620,10 +620,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) if (!svc_udp_get_dest_address(rqstp, cmh)) { net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n", cmh->cmsg_level, cmh->cmsg_type); -out_free: - trace_kfree_skb(skb, svc_udp_recvfrom); - skb_free_datagram_locked(svsk->sk_sk, skb); - return 0; + goto out_free; } rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp)); @@ -662,6 +659,10 @@ out_free: serv->sv_stats->netudpcnt++; return len; +out_free: + trace_kfree_skb(skb, svc_udp_recvfrom); + skb_free_datagram_locked(svsk->sk_sk, skb); + return 0; } static int -- cgit v1.2.2 From af6d572134b012ca92c4efc8a2f1cadbe5d01064 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 21 Aug 2012 17:22:11 -0400 Subject: svcrpc: don't bother checking bad svc_addr_len result None of the callers should see an unsupported address family (only one of them even bothers to check for that case), so just check for the buggy case in svc_addr_len and don't bother elsewhere. Acked-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_xprt.h | 3 +-- net/sunrpc/svcsock.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 73c7a68667ea..193dddab6511 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -167,8 +167,7 @@ static inline size_t svc_addr_len(const struct sockaddr *sa) case AF_INET6: return sizeof(struct sockaddr_in6); } - - return 0; + BUG(); } static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 06ae8a755349..406688baac57 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -601,8 +601,6 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) return -EAGAIN; } len = svc_addr_len(svc_addr(rqstp)); - if (len == 0) - return -EAFNOSUPPORT; rqstp->rq_addrlen = len; if (skb->tstamp.tv64 == 0) { skb->tstamp = ktime_get_real(); -- cgit v1.2.2 From 9f9d2ebe693a98d517257e1a39f61120b4473b96 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Aug 2012 21:35:24 -0400 Subject: svcrpc: make xpo_recvfrom return only >=0 The only errors returned from xpo_recvfrom have been -EAGAIN and -EAFNOSUPPORT. The latter was removed by a previous patch. That leaves only -EAGAIN, which is treated just like 0 by the caller (svc_recv). So, just ditch -EAGAIN and return 0 instead. Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 2 +- net/sunrpc/svcsock.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index ee15663798b3..3e317307e288 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -743,7 +743,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) svc_xprt_received(xprt); /* No data, incomplete (TCP) read, or accept() */ - if (len == 0 || len == -EAGAIN) + if (len <= 0) goto out; clear_bit(XPT_OLD, &xprt->xpt_flags); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 406688baac57..7aee54c3fe46 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -598,7 +598,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) dprintk("svc: recvfrom returned error %d\n", -err); set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); } - return -EAGAIN; + return 0; } len = svc_addr_len(svc_addr(rqstp)); rqstp->rq_addrlen = len; @@ -1174,13 +1174,13 @@ error: if (len != -EAGAIN) goto err_other; dprintk("RPC: TCP recvfrom got EAGAIN\n"); - return -EAGAIN; + return 0; err_other: printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_xprt.xpt_server->sv_name, -len); set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); err_noclose: - return -EAGAIN; /* record not complete */ + return 0; /* record not complete */ } /* -- cgit v1.2.2 From 5b444cc9a4c979aa0fa185c8ddca221462a34b7a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Aug 2012 21:47:53 -0400 Subject: svcrpc: remove handling of unknown errors from svc_recv svc_recv() returns only -EINTR or -EAGAIN. If we really want to worry about the case where it has a bug that causes it to return something else, we could stick a WARN() in svc_recv. But it's silly to require every caller to have all this boilerplate to handle that case. Signed-off-by: J. Bruce Fields --- fs/lockd/svc.c | 17 ++--------------- fs/nfs/callback.c | 16 ++-------------- fs/nfsd/nfssvc.c | 12 +----------- 3 files changed, 5 insertions(+), 40 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 31a63f87b806..e515569f0f8b 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -126,7 +126,7 @@ static void restart_grace(void) static int lockd(void *vrqstp) { - int err = 0, preverr = 0; + int err = 0; struct svc_rqst *rqstp = vrqstp; /* try_to_freeze() is called from svc_recv() */ @@ -165,21 +165,8 @@ lockd(void *vrqstp) * recvfrom routine. */ err = svc_recv(rqstp, timeout); - if (err == -EAGAIN || err == -EINTR) { - preverr = err; + if (err == -EAGAIN || err == -EINTR) continue; - } - if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "%s: unexpected error " - "from svc_recv (%d)\n", __func__, err); - preverr = err; - } - schedule_timeout_interruptible(HZ); - continue; - } - preverr = err; - dprintk("lockd: request from %s\n", svc_print_addr(rqstp, buf, sizeof(buf))); diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 4c8459e5bdee..d9e2a1880783 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -45,7 +45,7 @@ unsigned short nfs_callback_tcpport6; static int nfs4_callback_svc(void *vrqstp) { - int err, preverr = 0; + int err; struct svc_rqst *rqstp = vrqstp; set_freezable(); @@ -55,20 +55,8 @@ nfs4_callback_svc(void *vrqstp) * Listen for a request on the socket */ err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); - if (err == -EAGAIN || err == -EINTR) { - preverr = err; + if (err == -EAGAIN || err == -EINTR) continue; - } - if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "NFS: %s: unexpected error " - "from svc_recv (%d)\n", __func__, err); - preverr = err; - } - schedule_timeout_uninterruptible(HZ); - continue; - } - preverr = err; svc_process(rqstp); } return 0; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index dd2b7343d741..2013aa001dab 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -487,7 +487,7 @@ static int nfsd(void *vrqstp) { struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; - int err, preverr = 0; + int err; /* Lock module and set up kernel thread */ mutex_lock(&nfsd_mutex); @@ -534,16 +534,6 @@ nfsd(void *vrqstp) ; if (err == -EINTR) break; - else if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "%s: unexpected error " - "from svc_recv (%d)\n", __func__, -err); - preverr = err; - } - schedule_timeout_uninterruptible(HZ); - continue; - } - validate_process_creds(); svc_process(rqstp); validate_process_creds(); -- cgit v1.2.2 From 6741019c829ecfa6f7a504fae1305dcf5d5cf057 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Aug 2012 22:12:19 -0400 Subject: svcrpc: make svc_xprt_received static Note this isn't used outside svc_xprt.c. May as well move it so we don't need a declaration while we're here. Also remove an outdated comment. Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_xprt.h | 1 - net/sunrpc/svc_xprt.c | 41 ++++++++++++++++---------------- net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 ---- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 193dddab6511..b05963f09ebf 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -114,7 +114,6 @@ void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, int svc_create_xprt(struct svc_serv *, const char *, struct net *, const int, const unsigned short, int); void svc_xprt_enqueue(struct svc_xprt *xprt); -void svc_xprt_received(struct svc_xprt *); void svc_xprt_put(struct svc_xprt *xprt); void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); void svc_close_xprt(struct svc_xprt *xprt); diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 3e317307e288..295e6ed21ca0 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -208,6 +208,26 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); } +/* + * svc_xprt_received conditionally queues the transport for processing + * by another thread. The caller must hold the XPT_BUSY bit and must + * not thereafter touch transport data. + * + * Note: XPT_DATA only gets cleared when a read-attempt finds no (or + * insufficient) data. + */ +static void svc_xprt_received(struct svc_xprt *xprt) +{ + BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); + /* As soon as we clear busy, the xprt could be closed and + * 'put', so we need a reference to call svc_xprt_enqueue with: + */ + svc_xprt_get(xprt); + clear_bit(XPT_BUSY, &xprt->xpt_flags); + svc_xprt_enqueue(xprt); + svc_xprt_put(xprt); +} + void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) { clear_bit(XPT_TEMP, &new->xpt_flags); @@ -398,27 +418,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) return xprt; } -/* - * svc_xprt_received conditionally queues the transport for processing - * by another thread. The caller must hold the XPT_BUSY bit and must - * not thereafter touch transport data. - * - * Note: XPT_DATA only gets cleared when a read-attempt finds no (or - * insufficient) data. - */ -void svc_xprt_received(struct svc_xprt *xprt) -{ - BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); - /* As soon as we clear busy, the xprt could be closed and - * 'put', so we need a reference to call svc_xprt_enqueue with: - */ - svc_xprt_get(xprt); - clear_bit(XPT_BUSY, &xprt->xpt_flags); - svc_xprt_enqueue(xprt); - svc_xprt_put(xprt); -} -EXPORT_SYMBOL_GPL(svc_xprt_received); - /** * svc_reserve - change the space reserved for the reply to a request. * @rqstp: The request in question diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 73b428bef598..62e4f9bcc387 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -578,10 +578,6 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird) list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q); spin_unlock_bh(&listen_xprt->sc_lock); - /* - * Can't use svc_xprt_received here because we are not on a - * rqstp thread - */ set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags); svc_xprt_enqueue(&listen_xprt->sc_xprt); } -- cgit v1.2.2 From 6797fa5a018ff916a071c6265fbf043644abcd29 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sat, 18 Aug 2012 15:33:51 -0400 Subject: svcrpc: break up svc_recv Matter of taste, I suppose, but svc_recv breaks up naturally into: allocate pages and setup arg dequeue (wait for, if necessary) next socket do something with that socket And I find it easier to read when it doesn't go on for pages and pages. Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 103 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 36 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 295e6ed21ca0..6ebc9a95bbab 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -568,33 +568,12 @@ static void svc_check_conn_limits(struct svc_serv *serv) } } -/* - * Receive the next request on any transport. This code is carefully - * organised not to touch any cachelines in the shared svc_serv - * structure, only cachelines in the local svc_pool. - */ -int svc_recv(struct svc_rqst *rqstp, long timeout) +int svc_alloc_arg(struct svc_rqst *rqstp) { - struct svc_xprt *xprt = NULL; - struct svc_serv *serv = rqstp->rq_server; - struct svc_pool *pool = rqstp->rq_pool; - int len, i; - int pages; - struct xdr_buf *arg; - DECLARE_WAITQUEUE(wait, current); - long time_left; - - dprintk("svc: server %p waiting for data (to = %ld)\n", - rqstp, timeout); - - if (rqstp->rq_xprt) - printk(KERN_ERR - "svc_recv: service %p, transport not NULL!\n", - rqstp); - if (waitqueue_active(&rqstp->rq_wait)) - printk(KERN_ERR - "svc_recv: service %p, wait queue active!\n", - rqstp); + struct svc_serv *serv = rqstp->rq_server; + struct xdr_buf *arg; + int pages; + int i; /* now allocate needed pages. If we get a failure, sleep briefly */ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; @@ -624,11 +603,15 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) arg->page_len = (pages-2)*PAGE_SIZE; arg->len = (pages-1)*PAGE_SIZE; arg->tail[0].iov_len = 0; + return 0; +} - try_to_freeze(); - cond_resched(); - if (signalled() || kthread_should_stop()) - return -EINTR; +struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout) +{ + struct svc_xprt *xprt; + struct svc_pool *pool = rqstp->rq_pool; + DECLARE_WAITQUEUE(wait, current); + long time_left; /* Normally we will wait up to 5 seconds for any required * cache information to be provided. @@ -666,7 +649,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) if (kthread_should_stop()) { set_current_state(TASK_RUNNING); spin_unlock_bh(&pool->sp_lock); - return -EINTR; + return ERR_PTR(-EINTR); } add_wait_queue(&rqstp->rq_wait, &wait); @@ -687,19 +670,25 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) spin_unlock_bh(&pool->sp_lock); dprintk("svc: server %p, no data yet\n", rqstp); if (signalled() || kthread_should_stop()) - return -EINTR; + return ERR_PTR(-EINTR); else - return -EAGAIN; + return ERR_PTR(-EAGAIN); } } spin_unlock_bh(&pool->sp_lock); + return xprt; +} + +static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) +{ + struct svc_serv *serv = rqstp->rq_server; + int len = 0; - len = 0; if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { dprintk("svc_recv: found XPT_CLOSE\n"); svc_delete_xprt(xprt); /* Leave XPT_BUSY set on the dead xprt: */ - goto out; + return 0; } if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { struct svc_xprt *newxpt; @@ -727,8 +716,9 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) svc_xprt_received(newxpt); } } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) { + /* XPT_DATA|XPT_DEFERRED case: */ dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", - rqstp, pool->sp_id, xprt, + rqstp, rqstp->rq_pool->sp_id, xprt, atomic_read(&xprt->xpt_ref.refcount)); rqstp->rq_deferred = svc_deferred_dequeue(xprt); if (rqstp->rq_deferred) @@ -739,7 +729,48 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); } + /* clear XPT_BUSY: */ svc_xprt_received(xprt); + return len; +} + +/* + * Receive the next request on any transport. This code is carefully + * organised not to touch any cachelines in the shared svc_serv + * structure, only cachelines in the local svc_pool. + */ +int svc_recv(struct svc_rqst *rqstp, long timeout) +{ + struct svc_xprt *xprt = NULL; + struct svc_serv *serv = rqstp->rq_server; + int len, err; + + dprintk("svc: server %p waiting for data (to = %ld)\n", + rqstp, timeout); + + if (rqstp->rq_xprt) + printk(KERN_ERR + "svc_recv: service %p, transport not NULL!\n", + rqstp); + if (waitqueue_active(&rqstp->rq_wait)) + printk(KERN_ERR + "svc_recv: service %p, wait queue active!\n", + rqstp); + + err = svc_alloc_arg(rqstp); + if (err) + return err; + + try_to_freeze(); + cond_resched(); + if (signalled() || kthread_should_stop()) + return -EINTR; + + xprt = svc_get_next_xprt(rqstp, timeout); + if (IS_ERR(xprt)) + return PTR_ERR(xprt); + + len = svc_handle_xprt(rqstp, xprt); /* No data, incomplete (TCP) read, or accept() */ if (len <= 0) -- cgit v1.2.2 From 65b2e6656bda2ad983727fcc725ac66b6d5035a7 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sat, 18 Aug 2012 15:44:33 -0400 Subject: svcrpc: split up svc_handle_xprt Move initialization of newly accepted socket into a helper. Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 6ebc9a95bbab..194d865fae72 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -679,6 +679,23 @@ struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout) return xprt; } +void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt) +{ + spin_lock_bh(&serv->sv_lock); + set_bit(XPT_TEMP, &newxpt->xpt_flags); + list_add(&newxpt->xpt_list, &serv->sv_tempsocks); + serv->sv_tmpcnt++; + if (serv->sv_temptimer.function == NULL) { + /* setup timer to age temp transports */ + setup_timer(&serv->sv_temptimer, svc_age_temp_xprts, + (unsigned long)serv); + mod_timer(&serv->sv_temptimer, + jiffies + svc_conn_age_period * HZ); + } + spin_unlock_bh(&serv->sv_lock); + svc_xprt_received(newxpt); +} + static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) { struct svc_serv *serv = rqstp->rq_server; @@ -692,29 +709,15 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) } if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { struct svc_xprt *newxpt; + /* + * We know this module_get will succeed because the + * listener holds a reference too + */ + __module_get(xprt->xpt_class->xcl_owner); + svc_check_conn_limits(xprt->xpt_server); newxpt = xprt->xpt_ops->xpo_accept(xprt); - if (newxpt) { - /* - * We know this module_get will succeed because the - * listener holds a reference too - */ - __module_get(newxpt->xpt_class->xcl_owner); - svc_check_conn_limits(xprt->xpt_server); - spin_lock_bh(&serv->sv_lock); - set_bit(XPT_TEMP, &newxpt->xpt_flags); - list_add(&newxpt->xpt_list, &serv->sv_tempsocks); - serv->sv_tmpcnt++; - if (serv->sv_temptimer.function == NULL) { - /* setup timer to age temp transports */ - setup_timer(&serv->sv_temptimer, - svc_age_temp_xprts, - (unsigned long)serv); - mod_timer(&serv->sv_temptimer, - jiffies + svc_conn_age_period * HZ); - } - spin_unlock_bh(&serv->sv_lock); - svc_xprt_received(newxpt); - } + if (newxpt) + svc_add_new_temp_xprt(serv, newxpt); } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) { /* XPT_DATA|XPT_DEFERRED case: */ dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", -- cgit v1.2.2 From 8a4c6e19cfed5e650045312affed7e6056383278 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 15 Aug 2012 17:43:30 -0400 Subject: nfsd: document kernel interfaces for nfsd configuration These are only needed by nfs-utils. But I needed to remind myself how they worked recently and thought this might be helpful. It's short and incomplete for now as I was only interested in startup, shutdown, and configuration of listening sockets. Signed-off-by: J. Bruce Fields --- .../filesystems/nfs/nfsd-admin-interfaces.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/filesystems/nfs/nfsd-admin-interfaces.txt diff --git a/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt new file mode 100644 index 000000000000..56a96fb08a73 --- /dev/null +++ b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt @@ -0,0 +1,41 @@ +Administrative interfaces for nfsd +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note that normally these interfaces are used only by the utilities in +nfs-utils. + +nfsd is controlled mainly by pseudofiles under the "nfsd" filesystem, +which is normally mounted at /proc/fs/nfsd/. + +The server is always started by the first write of a nonzero value to +nfsd/threads. + +Before doing that, NFSD can be told which sockets to listen on by +writing to nfsd/portlist; that write may be: + + - an ascii-encoded file descriptor, which should refer to a + bound (and listening, for tcp) socket, or + - "transportname port", where transportname is currently either + "udp", "tcp", or "rdma". + +If nfsd is started without doing any of these, then it will create one +udp and one tcp listener at port 2049 (see nfsd_init_socks). + +On startup, nfsd and lockd grace periods start. + +nfsd is shut down by a write of 0 to nfsd/threads. All locks and state +are thrown away at that point. + +Between startup and shutdown, the number of threads may be adjusted up +or down by additional writes to nfsd/threads or by writes to +nfsd/pool_threads. + +For more detail about files under nfsd/ and what they control, see +fs/nfsd/nfsctl.c; most of them have detailed comments. + +Implementation notes +^^^^^^^^^^^^^^^^^^^^ + +Note that the rpc server requires the caller to serialize addition and +removal of listening sockets, and startup and shutdown of the server. +For nfsd this is done using nfsd_mutex. -- cgit v1.2.2 From cf9182e90b2af04245ac4fae497fe73fc71285b4 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 29 Aug 2012 15:21:58 -0700 Subject: nfsd4: fix nfs4 stateid leak Processes that open and close multiple files may end up setting this oo_last_closed_stid without freeing what was previously pointed to. This can result in a major leak, visible for example by watching the nfsd4_stateids line of /proc/slabinfo. Reported-by: Cyril B. Tested-by: Cyril B. Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 5f1a91a9cd35..6686e747223f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3766,6 +3766,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); nfsd4_close_open_stateid(stp); + release_last_closed_stateid(oo); oo->oo_last_closed_stid = stp; if (list_empty(&oo->oo_owner.so_stateids)) { -- cgit v1.2.2 From eccf50c129686de11358093839749c83f6cae5db Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 15 Aug 2012 18:07:43 -0400 Subject: nfsd: remove unused listener-removal interfaces You can use nfsd/portlist to give nfsd additional sockets to listen on. In theory you can also remove listening sockets this way. But nobody's ever done that as far as I can tell. Also this was partially broken in 2.6.25, by a217813f9067b785241cb7f31956e51d2071703a "knfsd: Support adding transports by writing portlist file". (Note that we decide whether to take the "delfd" case by checking for a digit--but what's actually expected in that case is something made by svc_one_sock_name(), which won't begin with a digit.) So, let's just rip out this stuff. Acked-by: NeilBrown Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsctl.c | 78 ------------------------------------------ include/linux/sunrpc/svcsock.h | 3 -- net/sunrpc/svcsock.c | 51 --------------------------- 3 files changed, 132 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index e41a08ffbe0a..dab350dfc376 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -682,25 +682,6 @@ static ssize_t __write_ports_addfd(char *buf) return err; } -/* - * A '-' followed by the 'name' of a socket means we close the socket. - */ -static ssize_t __write_ports_delfd(char *buf) -{ - char *toclose; - int len = 0; - - toclose = kstrdup(buf + 1, GFP_KERNEL); - if (toclose == NULL) - return -ENOMEM; - - if (nfsd_serv != NULL) - len = svc_sock_names(nfsd_serv, buf, - SIMPLE_TRANSACTION_LIMIT, toclose); - kfree(toclose); - return len; -} - /* * A transport listener is added by writing it's transport name and * a port number. @@ -746,31 +727,6 @@ out_err: return err; } -/* - * A transport listener is removed by writing a "-", it's transport - * name, and it's port number. - */ -static ssize_t __write_ports_delxprt(char *buf) -{ - struct svc_xprt *xprt; - char transport[16]; - int port; - - if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) - return -EINVAL; - - if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) - return -EINVAL; - - xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); - if (xprt == NULL) - return -ENOTCONN; - - svc_close_xprt(xprt); - svc_xprt_put(xprt); - return 0; -} - static ssize_t __write_ports(struct file *file, char *buf, size_t size) { if (size == 0) @@ -779,15 +735,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) if (isdigit(buf[0])) return __write_ports_addfd(buf); - if (buf[0] == '-' && isdigit(buf[1])) - return __write_ports_delfd(buf); - if (isalpha(buf[0])) return __write_ports_addxprt(buf); - if (buf[0] == '-' && isalpha(buf[1])) - return __write_ports_delxprt(buf); - return -EINVAL; } @@ -825,21 +775,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) * OR * * Input: - * buf: C string containing a "-" followed - * by an integer value representing a - * previously passed in socket file - * descriptor - * size: non-zero length of C string in @buf - * Output: - * On success: NFS service no longer listens on that socket; - * passed-in buffer filled with a '\n'-terminated C - * string containing a unique name of the listener; - * return code is the size in bytes of the string - * On error: return code is a negative errno value - * - * OR - * - * Input: * buf: C string containing a transport * name and an unsigned integer value * representing the port to listen on, @@ -848,19 +783,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) * Output: * On success: returns zero; NFS service is started * On error: return code is a negative errno value - * - * OR - * - * Input: - * buf: C string containing a "-" followed - * by a transport name and an unsigned - * integer value representing the port - * to listen on, separated by whitespace - * size: non-zero length of C string in @buf - * Output: - * On success: returns zero; NFS service no longer listens - * on that transport - * On error: return code is a negative errno value */ static ssize_t write_ports(struct file *file, char *buf, size_t size) { diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index cb4ac69e1f33..92ad02f0dcc0 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -39,9 +39,6 @@ int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); -int svc_sock_names(struct svc_serv *serv, char *buf, - const size_t buflen, - const char *toclose); int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, const size_t len); void svc_init_xprt_sock(void); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 7aee54c3fe46..03827cef1fa7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -305,57 +305,6 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) return len; } -/** - * svc_sock_names - construct a list of listener names in a string - * @serv: pointer to RPC service - * @buf: pointer to a buffer to fill in with socket names - * @buflen: size of the buffer to be filled - * @toclose: pointer to '\0'-terminated C string containing the name - * of a listener to be closed - * - * Fills in @buf with a '\n'-separated list of names of listener - * sockets. If @toclose is not NULL, the socket named by @toclose - * is closed, and is not included in the output list. - * - * Returns positive length of the socket name string, or a negative - * errno value on error. - */ -int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, - const char *toclose) -{ - struct svc_sock *svsk, *closesk = NULL; - int len = 0; - - if (!serv) - return 0; - - spin_lock_bh(&serv->sv_lock); - list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { - int onelen = svc_one_sock_name(svsk, buf + len, buflen - len); - if (onelen < 0) { - len = onelen; - break; - } - if (toclose && strcmp(toclose, buf + len) == 0) { - closesk = svsk; - svc_xprt_get(&closesk->sk_xprt); - } else - len += onelen; - } - spin_unlock_bh(&serv->sv_lock); - - if (closesk) { - /* Should unregister with portmap, but you cannot - * unregister just one protocol... - */ - svc_close_xprt(&closesk->sk_xprt); - svc_xprt_put(&closesk->sk_xprt); - } else if (toclose) - return -ENOENT; - return len; -} -EXPORT_SYMBOL_GPL(svc_sock_names); - /* * Check input queue length */ -- cgit v1.2.2 From 92566e287d5211774f9466e35d7b7240532521e6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 25 Aug 2012 21:57:04 +0200 Subject: fs/nfsd/nfs4idmap.c: adjust inconsistent IS_ERR and PTR_ERR Change the call to PTR_ERR to access the value just tested by IS_ERR. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e,e1; @@ ( if (IS_ERR(e)) { ... PTR_ERR(e) ... } | if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } | *if (IS_ERR(e)) { ... * PTR_ERR(e1) ... } ) // Signed-off-by: Julia Lawall Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4idmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index fdc91a6fc9c4..11df4aca89ba 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -478,7 +478,7 @@ nfsd_idmap_init(struct net *net) goto destroy_idtoname_cache; nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); if (IS_ERR(nn->nametoid_cache)) { - rv = PTR_ERR(nn->idtoname_cache); + rv = PTR_ERR(nn->nametoid_cache); goto unregister_idtoname_cache; } rv = cache_register_net(nn->nametoid_cache, net); -- cgit v1.2.2 From ef79859e04bd67638f72373bb5514211d6f6d5b3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 29 Aug 2012 10:32:54 -0700 Subject: nfsd4: eliminate redundant nfs4_free_stateid Somehow we ended up with identical functions "nfs4_free_stateid" and "free_generic_stateid". Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6686e747223f..5122e1704cd4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2705,11 +2705,6 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st return nfs_ok; } -static void nfs4_free_stateid(struct nfs4_ol_stateid *s) -{ - kmem_cache_free(stateid_slab, s); -} - static inline int nfs4_access_to_access(u32 nfs4_access) { int flags = 0; @@ -3088,7 +3083,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) if (open->op_file) nfsd4_free_file(open->op_file); if (open->op_stp) - nfs4_free_stateid(open->op_stp); + free_generic_stateid(open->op_stp); } __be32 -- cgit v1.2.2 From 8c8651b8e2d2957e94c19bc72fd6b7cf9b47fce8 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 29 Aug 2012 10:10:53 -0400 Subject: nfsd: remove duplicate init in nfsd4_cb_recall remove duplicate init in nfsd4_cb_recall Signed-off-by: Namjae Jeon Signed-off-by: Vivek Trivedi Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 4c7bd35b1876..bdf29c96e4cd 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1028,7 +1028,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) cb->cb_msg.rpc_cred = callback_cred; cb->cb_ops = &nfsd4_cb_recall_ops; - dp->dl_retries = 1; INIT_LIST_HEAD(&cb->cb_per_client); cb->cb_done = true; -- cgit v1.2.2 From 9959ba0c241a71c7ed8133401cfbbee2720da0b5 Mon Sep 17 00:00:00 2001 From: Malahal Naineni Date: Sun, 9 Sep 2012 10:25:47 -0500 Subject: NFSD: pass null terminated buf to kstrtouint() The 'buf' is prepared with null termination with intention of using it for this purpose, but 'name' is passed instead! Signed-off-by: Malahal Naineni Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4idmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 11df4aca89ba..a1f10c0a6255 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -598,7 +598,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel /* Just to make sure it's null-terminated: */ memcpy(buf, name, namelen); buf[namelen] = '\0'; - ret = kstrtouint(name, 10, id); + ret = kstrtouint(buf, 10, id); return ret == 0; } -- cgit v1.2.2 From fac7a17b5fd056db969e4b3ec9936679c01f25a5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 14:16:55 -0400 Subject: nfsd4: cast readlink() bug argument As we already do in readv, writev. Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a9269f142cc4..e76a17e003c5 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1581,7 +1581,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = inode->i_op->readlink(path.dentry, buf, *lenp); + host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp); set_fs(oldfs); if (host_err < 0) -- cgit v1.2.2 From 6e67b5d1840b5788875ad561f2e76a1bf5facc86 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Sep 2012 09:49:43 -0400 Subject: nfsd4: fix bind_conn_to_session xdr comment Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6322df36031f..fd548d155088 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2659,7 +2659,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); WRITE32(bcts->dir); - /* XXX: ? */ + /* Sorry, we do not yet support RDMA over 4.1: */ WRITE32(0); ADJUST_ARGS(); } -- cgit v1.2.2 From 68eb35081e297b37db49d854cda144c6a3397699 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 21 Aug 2012 12:48:30 -0400 Subject: nfsd4: don't pin clientids to pseudoflavors I added cr_flavor to the data compared in same_creds without any justification, in d5497fc693a446ce9100fcf4117c3f795ddfd0d2 "nfsd4: move rq_flavor into svc_cred". Recent client changes then started making mount -osec=krb5 server:/export /mnt/ echo "hello" >/mnt/TMP umount /mnt/ mount -osec=krb5i server:/export /mnt/ echo "hello" >/mnt/TMP to fail due to a clid_inuse on the second open. Mounting sequentially like this with different flavors probably isn't that common outside artificial tests. Also, the real bug here may be that the server isn't just destroying the former clientid in this case (because it isn't good enough at recognizing when the old state is gone). But it prompted some discussion and a look back at the spec, and I think the check was probably wrong. Fix and document. Cc: stable@kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 5122e1704cd4..0f8d7e7922eb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1223,10 +1223,26 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2) return true; } +/* + * RFC 3530 language requires clid_inuse be returned when the + * "principal" associated with a requests differs from that previously + * used. We use uid, gid's, and gss principal string as our best + * approximation. We also don't want to allow non-gss use of a client + * established using gss: in theory cr_principal should catch that + * change, but in practice cr_principal can be null even in the gss case + * since gssd doesn't always pass down a principal string. + */ +static bool is_gss_cred(struct svc_cred *cr) +{ + /* Is cr_flavor one of the gss "pseudoflavors"?: */ + return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); +} + + static bool same_creds(struct svc_cred *cr1, struct svc_cred *cr2) { - if ((cr1->cr_flavor != cr2->cr_flavor) + if ((is_gss_cred(cr1) != is_gss_cred(cr2)) || (cr1->cr_uid != cr2->cr_uid) || (cr1->cr_gid != cr2->cr_gid) || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) -- cgit v1.2.2 From c116a0af76424c72d91ebff7646639cb1287bf63 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 11 Sep 2012 14:53:09 -0400 Subject: nfsd4: set cl_minorversion at create time And remove some mostly obsolete comments. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0f8d7e7922eb..73029cd0c5b6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1667,6 +1667,7 @@ out_new: status = nfserr_jukebox; goto out; } + new->cl_minorversion = 1; gen_clid(new); add_to_unconfirmed(new, strhashval); @@ -1799,12 +1800,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, status = nfserr_stale_clientid; goto out; } - - /* - * XXX: we should probably set this at creation time, and check - * for consistent minorversion use throughout: - */ - conf->cl_minorversion = 1; /* * We do not support RDMA or persistent sessions */ @@ -2216,10 +2211,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, copy_clid(new, conf); else /* case 4 (new client) or cases 2, 3 (client reboot): */ gen_clid(new); - /* - * XXX: we should probably set this at creation time, and check - * for consistent minorversion use throughout: - */ new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); add_to_unconfirmed(new, strhashval); -- cgit v1.2.2 From d15c077e442d3c4167aaac87b3b7fe8ccad67a1f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Sep 2012 16:19:31 -0400 Subject: nfsd4: enforce per-client sessions/no-sessions distinction Something like creating a client with setclientid and then trying to confirm it with create_session may not crash the server, but I'm not completely positive of that, and in any case it's obviously bad client behavior. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4state.c | 49 +++++++++++++++++++++++++++++-------------------- fs/nfsd/state.h | 2 +- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f2bb0ef67b2a..6c9a4b291dba 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -370,7 +370,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_PREVIOUS: open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; - status = nfs4_check_open_reclaim(&open->op_clientid); + status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); if (status) goto out; case NFS4_OPEN_CLAIM_FH: diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 73029cd0c5b6..550784219030 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1356,13 +1356,15 @@ move_to_confirmed(struct nfs4_client *clp) } static struct nfs4_client * -find_confirmed_client(clientid_t *clid) +find_confirmed_client(clientid_t *clid, bool sessions) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) { + if ((bool)clp->cl_minorversion != sessions) + return NULL; renew_client(clp); return clp; } @@ -1371,14 +1373,17 @@ find_confirmed_client(clientid_t *clid) } static struct nfs4_client * -find_unconfirmed_client(clientid_t *clid) +find_unconfirmed_client(clientid_t *clid, bool sessions) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { - if (same_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) { + if ((bool)clp->cl_minorversion != sessions) + return NULL; return clp; + } } return NULL; } @@ -1768,8 +1773,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, return nfserr_inval; nfs4_lock_state(); - unconf = find_unconfirmed_client(&cr_ses->clientid); - conf = find_confirmed_client(&cr_ses->clientid); + unconf = find_unconfirmed_client(&cr_ses->clientid, true); + conf = find_confirmed_client(&cr_ses->clientid, true); if (conf) { cs_slot = &conf->cl_cs_slot; @@ -2096,8 +2101,8 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta __be32 status = 0; nfs4_lock_state(); - unconf = find_unconfirmed_client(&dc->clientid); - conf = find_confirmed_client(&dc->clientid); + unconf = find_unconfirmed_client(&dc->clientid, true); + conf = find_confirmed_client(&dc->clientid, true); if (conf) { clp = conf; @@ -2239,8 +2244,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, return nfserr_stale_clientid; nfs4_lock_state(); - conf = find_confirmed_client(clid); - unconf = find_unconfirmed_client(clid); + conf = find_confirmed_client(clid, false); + unconf = find_unconfirmed_client(clid, false); /* * We try hard to give out unique clientid's, so if we get an * attempt to confirm the same clientid with a different cred, @@ -2454,16 +2459,20 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, } static struct nfs4_openowner * -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) { struct nfs4_stateowner *so; struct nfs4_openowner *oo; + struct nfs4_client *clp; list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { if (!so->so_is_open_owner) continue; if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { oo = openowner(so); + clp = oo->oo_owner.so_client; + if ((bool)clp->cl_minorversion != sessions) + return NULL; renew_client(oo->oo_owner.so_client); return oo; } @@ -2607,10 +2616,10 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, return nfserr_jukebox; strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); - oo = find_openstateowner_str(strhashval, open); + oo = find_openstateowner_str(strhashval, open, cstate->minorversion); open->op_openowner = oo; if (!oo) { - clp = find_confirmed_client(clientid); + clp = find_confirmed_client(clientid, cstate->minorversion); if (clp == NULL) return nfserr_expired; goto new_owner; @@ -3107,7 +3116,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_stale_clientid; if (STALE_CLIENTID(clid, nn)) goto out; - clp = find_confirmed_client(clid); + clp = find_confirmed_client(clid, cstate->minorversion); status = nfserr_expired; if (clp == NULL) { /* We assume the client took too long to RENEW. */ @@ -3375,7 +3384,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) return nfs_ok; } -static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) +static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) { struct nfs4_client *cl; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -3384,7 +3393,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s return nfserr_bad_stateid; if (STALE_STATEID(stateid, nn)) return nfserr_stale_stateid; - cl = find_confirmed_client(&stateid->si_opaque.so_clid); + cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); if (!cl) return nfserr_expired; *s = find_stateid_by_type(cl, stateid, typemask); @@ -3417,7 +3426,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return check_special_stateids(net, current_fh, stateid, flags); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); if (status) return status; status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); @@ -3567,7 +3576,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, seqid, STATEID_VAL(stateid)); *stpp = NULL; - status = nfsd4_lookup_stateid(stateid, typemask, &s); + status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); if (status) return status; *stpp = openlockstateid(s); @@ -3805,7 +3814,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, inode = cstate->current_fh.fh_dentry->d_inode; nfs4_lock_state(); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); if (status) goto out; dp = delegstateid(s); @@ -4533,12 +4542,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) * Called from OPEN. Look for clientid in reclaim list. */ __be32 -nfs4_check_open_reclaim(clientid_t *clid) +nfs4_check_open_reclaim(clientid_t *clid, bool sessions) { struct nfs4_client *clp; /* find clientid in conf_id_hashtbl */ - clp = find_confirmed_client(clid); + clp = find_confirmed_client(clid, sessions); if (clp == NULL) return nfserr_reclaim_bad; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ec513fd4bae9..e036894bce57 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -455,7 +455,7 @@ extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); extern void nfs4_release_reclaim(void); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); -extern __be32 nfs4_check_open_reclaim(clientid_t *clid); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern int set_callback_cred(void); -- cgit v1.2.2 From 497305014864ea9e32adf7e8a06081209a5e7c42 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 11 Sep 2012 15:33:21 -0400 Subject: nfsd4: reject bad forechannel attrs earlier This could simplify the logic a little later. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 550784219030..64938ca05c6d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1771,6 +1771,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) return nfserr_inval; + if (check_forechannel_attrs(cr_ses->fore_channel)) + return nfserr_toosmall; nfs4_lock_state(); unconf = find_unconfirmed_client(&cr_ses->clientid, true); @@ -1811,10 +1813,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, cr_ses->flags &= ~SESSION4_PERSIST; cr_ses->flags &= ~SESSION4_RDMA; - status = nfserr_toosmall; - if (check_forechannel_attrs(cr_ses->fore_channel)) - goto out; - status = nfserr_jukebox; new = alloc_init_session(rqstp, conf, cr_ses); if (!new) -- cgit v1.2.2 From 3ba6367124f3f07c91ea45a3ea24bbf4c5429bfc Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 11 Sep 2012 15:37:40 -0400 Subject: nfsd4: separate connection allocation and initialization It'll be useful to have connection allocation and initialization as separate functions. Also, note we'd been ignoring the alloc_conn error return in bind_conn_to_session. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 64938ca05c6d..101ccd856e6a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -852,14 +852,10 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); } -static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) +static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses, u32 dir) { - struct nfsd4_conn *conn; int ret; - conn = alloc_conn(rqstp, dir); - if (!conn) - return nfserr_jukebox; nfsd4_hash_conn(conn, ses); ret = nfsd4_register_conn(conn); if (ret) @@ -870,17 +866,21 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, /* callback channel may be back up */ nfsd4_probe_callback(ses->se_client); } - return nfs_ok; } static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) { + struct nfsd4_conn *conn; u32 dir = NFS4_CDFC4_FORE; if (ses->se_flags & SESSION4_BACK_CHAN) dir |= NFS4_CDFC4_BACK; - return nfsd4_new_conn(rqstp, ses, dir); + conn = alloc_conn(rqstp, dir); + if (!conn) + return nfserr_jukebox; + nfsd4_init_conn(rqstp, conn, ses, dir); + return nfs_ok; } /* must be called under client_lock */ @@ -1868,6 +1868,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, struct nfsd4_bind_conn_to_session *bcts) { __be32 status; + struct nfsd4_conn *conn; if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; @@ -1884,9 +1885,13 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, return nfserr_badsession; status = nfsd4_map_bcts_dir(&bcts->dir); - if (!status) - nfsd4_new_conn(rqstp, cstate->session, bcts->dir); - return status; + if (status) + return status; + conn = alloc_conn(rqstp, bcts->dir); + if (!conn) + return nfserr_jukebox; + nfsd4_init_conn(rqstp, conn, cstate->session, bcts->dir); + return nfs_ok; } static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) -- cgit v1.2.2 From e1ff371f9da57c1965400b9cc6607705d76a67bd Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 11 Sep 2012 17:10:25 -0400 Subject: nfsd4: new_conn_from_crses should only allocate Do the initialization in the caller, and clarify that the only failure ever possible here was due to allocation. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 101ccd856e6a..8b7f8f84d5a4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -852,7 +852,7 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); } -static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses, u32 dir) +static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) { int ret; @@ -862,25 +862,19 @@ static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, str /* oops; xprt is already down: */ nfsd4_conn_lost(&conn->cn_xpt_user); if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN && - dir & NFS4_CDFC4_BACK) { + conn->cn_flags & NFS4_CDFC4_BACK) { /* callback channel may be back up */ nfsd4_probe_callback(ses->se_client); } } -static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) +static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) { - struct nfsd4_conn *conn; u32 dir = NFS4_CDFC4_FORE; - if (ses->se_flags & SESSION4_BACK_CHAN) + if (cses->flags & SESSION4_BACK_CHAN) dir |= NFS4_CDFC4_BACK; - - conn = alloc_conn(rqstp, dir); - if (!conn) - return nfserr_jukebox; - nfsd4_init_conn(rqstp, conn, ses, dir); - return nfs_ok; + return alloc_conn(rqstp, dir); } /* must be called under client_lock */ @@ -929,9 +923,9 @@ void nfsd4_put_session(struct nfsd4_session *ses) static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) { struct nfsd4_session *new; + struct nfsd4_conn *conn; struct nfsd4_channel_attrs *fchan = &cses->fore_channel; int numslots, slotsize; - __be32 status; int idx; /* @@ -970,14 +964,14 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n spin_unlock(&clp->cl_lock); spin_unlock(&client_lock); - status = nfsd4_new_conn_from_crses(rqstp, new); - /* whoops: benny points out, status is ignored! (err, or bogus) */ - if (status) { + conn = alloc_conn_from_crses(rqstp, cses); + if (!conn) { spin_lock(&client_lock); free_session(&new->se_ref); spin_unlock(&client_lock); return NULL; } + nfsd4_init_conn(rqstp, conn, new); if (cses->flags & SESSION4_BACK_CHAN) { struct sockaddr *sa = svc_addr(rqstp); /* @@ -1890,7 +1884,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, conn = alloc_conn(rqstp, bcts->dir); if (!conn) return nfserr_jukebox; - nfsd4_init_conn(rqstp, conn, cstate->session, bcts->dir); + nfsd4_init_conn(rqstp, conn, cstate->session); return nfs_ok; } -- cgit v1.2.2 From 1377b69e68241826761d257ac26dd4285c3f9e9b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 11 Sep 2012 21:42:40 -0400 Subject: nfsd4: minor free_session cleanup Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8b7f8f84d5a4..7536a88063a5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -897,20 +897,21 @@ static void nfsd4_del_conns(struct nfsd4_session *s) spin_unlock(&clp->cl_lock); } +static void __free_session(struct nfsd4_session *ses) +{ + nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); + free_session_slots(ses); + kfree(ses); +} + static void free_session(struct kref *kref) { struct nfsd4_session *ses; - int mem; lockdep_assert_held(&client_lock); ses = container_of(kref, struct nfsd4_session, se_ref); nfsd4_del_conns(ses); - spin_lock(&nfsd_drc_lock); - mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); - nfsd_drc_mem_used -= mem; - spin_unlock(&nfsd_drc_lock); - free_session_slots(ses); - kfree(ses); + __free_session(ses); } void nfsd4_put_session(struct nfsd4_session *ses) @@ -966,9 +967,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n conn = alloc_conn_from_crses(rqstp, cses); if (!conn) { - spin_lock(&client_lock); - free_session(&new->se_ref); - spin_unlock(&client_lock); + __free_session(new); return NULL; } nfsd4_init_conn(rqstp, conn, new); -- cgit v1.2.2 From a827bcb242ecc884d38af8145e1d9a112b739b35 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 12 Sep 2012 09:51:34 -0400 Subject: nfsd4: clean up session allocation Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7536a88063a5..79f1fdb22dc7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -758,7 +758,7 @@ static void nfsd4_put_drc_mem(int slotsize, int num) spin_unlock(&nfsd_drc_lock); } -static struct nfsd4_session *alloc_session(int slotsize, int numslots) +static struct nfsd4_session *__alloc_session(int slotsize, int numslots) { struct nfsd4_session *new; int mem, i; @@ -921,14 +921,10 @@ void nfsd4_put_session(struct nfsd4_session *ses) spin_unlock(&client_lock); } -static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) { struct nfsd4_session *new; - struct nfsd4_conn *conn; - struct nfsd4_channel_attrs *fchan = &cses->fore_channel; int numslots, slotsize; - int idx; - /* * Note decreasing slot size below client's request may * make it difficult for client to function correctly, whereas @@ -941,13 +937,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n if (numslots < 1) return NULL; - new = alloc_session(slotsize, numslots); + new = __alloc_session(slotsize, numslots); if (!new) { nfsd4_put_drc_mem(slotsize, fchan->maxreqs); return NULL; } init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); + return new; +} +static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) +{ + struct nfsd4_session *new; + struct nfsd4_conn *conn; + int idx; + + new = alloc_session(&cses->fore_channel); + if (!new) + return NULL; + + conn = alloc_conn_from_crses(rqstp, cses); + if (!conn) { + __free_session(new); + return NULL; + } new->se_client = clp; gen_sessionid(new); @@ -965,11 +978,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n spin_unlock(&clp->cl_lock); spin_unlock(&client_lock); - conn = alloc_conn_from_crses(rqstp, cses); - if (!conn) { - __free_session(new); - return NULL; - } nfsd4_init_conn(rqstp, conn, new); if (cses->flags & SESSION4_BACK_CHAN) { struct sockaddr *sa = svc_addr(rqstp); -- cgit v1.2.2 From 81f0b2a4965da2a48aed5e992f2bc859e5d35066 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 12 Sep 2012 11:04:33 -0400 Subject: nfsd4: separate session allocation and initialization This will allow some further simplification. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 79f1fdb22dc7..1cd80d576952 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -946,21 +946,10 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) return new; } -static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) +static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) { - struct nfsd4_session *new; - struct nfsd4_conn *conn; int idx; - new = alloc_session(&cses->fore_channel); - if (!new) - return NULL; - - conn = alloc_conn_from_crses(rqstp, cses); - if (!conn) { - __free_session(new); - return NULL; - } new->se_client = clp; gen_sessionid(new); @@ -978,7 +967,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n spin_unlock(&clp->cl_lock); spin_unlock(&client_lock); - nfsd4_init_conn(rqstp, conn, new); if (cses->flags & SESSION4_BACK_CHAN) { struct sockaddr *sa = svc_addr(rqstp); /* @@ -1766,6 +1754,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, struct sockaddr *sa = svc_addr(rqstp); struct nfs4_client *conf, *unconf; struct nfsd4_session *new; + struct nfsd4_conn *conn; struct nfsd4_clid_slot *cs_slot = NULL; bool confirm_me = false; __be32 status = 0; @@ -1774,6 +1763,13 @@ nfsd4_create_session(struct svc_rqst *rqstp, return nfserr_inval; if (check_forechannel_attrs(cr_ses->fore_channel)) return nfserr_toosmall; + new = alloc_session(&cr_ses->fore_channel); + if (!new) + return nfserr_jukebox; + status = nfserr_jukebox; + conn = alloc_conn_from_crses(rqstp, cr_ses); + if (!conn) + goto out_free_session; nfs4_lock_state(); unconf = find_unconfirmed_client(&cr_ses->clientid, true); @@ -1784,41 +1780,40 @@ nfsd4_create_session(struct svc_rqst *rqstp, status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); if (status == nfserr_replay_cache) { status = nfsd4_replay_create_session(cr_ses, cs_slot); - goto out; + goto out_free_conn; } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { status = nfserr_seq_misordered; - goto out; + goto out_free_conn; } } else if (unconf) { if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { status = nfserr_clid_inuse; - goto out; + goto out_free_conn; } cs_slot = &unconf->cl_cs_slot; status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); if (status) { /* an unconfirmed replay returns misordered */ status = nfserr_seq_misordered; - goto out; + goto out_free_conn; } confirm_me = true; conf = unconf; } else { status = nfserr_stale_clientid; - goto out; + goto out_free_conn; } + status = nfs_ok; /* * We do not support RDMA or persistent sessions */ cr_ses->flags &= ~SESSION4_PERSIST; cr_ses->flags &= ~SESSION4_RDMA; - status = nfserr_jukebox; - new = alloc_init_session(rqstp, conf, cr_ses); - if (!new) - goto out; - status = nfs_ok; + init_session(rqstp, new, conf, cr_ses); + nfsd4_init_conn(rqstp, conn, new); + memcpy(cr_ses->sessionid.data, new->se_sessionid.data, NFS4_MAX_SESSIONID_LEN); memcpy(&cr_ses->fore_channel, &new->se_fchannel, @@ -1840,6 +1835,11 @@ out: nfs4_unlock_state(); dprintk("%s returns %d\n", __func__, ntohl(status)); return status; +out_free_conn: + free_conn(conn); +out_free_session: + __free_session(new); + goto out; } static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) -- cgit v1.2.2 From 8f9d3d3b7cd25763efec91db23a1cce1971147c2 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 12 Sep 2012 14:41:31 -0400 Subject: nfsd4: expire old client earlier Before we had to delay expiring a client till we'd found out whether the session and connection allocations would succeed. That's no longer necessary. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1cd80d576952..592cd7fb6f00 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1756,7 +1756,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, struct nfsd4_session *new; struct nfsd4_conn *conn; struct nfsd4_clid_slot *cs_slot = NULL; - bool confirm_me = false; __be32 status = 0; if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) @@ -1786,6 +1785,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, goto out_free_conn; } } else if (unconf) { + unsigned int hash; + struct nfs4_client *old; if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { status = nfserr_clid_inuse; @@ -1798,7 +1799,11 @@ nfsd4_create_session(struct svc_rqst *rqstp, status = nfserr_seq_misordered; goto out_free_conn; } - confirm_me = true; + hash = clientstr_hashval(unconf->cl_recdir); + old = find_confirmed_client_by_str(unconf->cl_recdir, hash); + if (old) + expire_client(old); + move_to_confirmed(unconf); conf = unconf; } else { status = nfserr_stale_clientid; @@ -1823,14 +1828,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, /* cache solo and embedded create sessions under the state lock */ nfsd4_cache_create_session(cr_ses, cs_slot, status); - if (confirm_me) { - unsigned int hash = clientstr_hashval(unconf->cl_recdir); - struct nfs4_client *old = - find_confirmed_client_by_str(conf->cl_recdir, hash); - if (old) - expire_client(old); - move_to_confirmed(conf); - } out: nfs4_unlock_state(); dprintk("%s returns %d\n", __func__, ntohl(status)); -- cgit v1.2.2 From 6a3b15634279aa6740f9b829d25db32024b2ca7c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 12 Sep 2012 09:59:17 -0400 Subject: nfsd4: remove redundant callback probe Both nfsd4_init_conn and alloc_init_session are probing the callback channel, harmless but pointless. Also, nfsd4_init_conn should probably be probing in the "unknown" case as well. In fact I don't see any harm to just doing it unconditionally when we get a new backchannel connection. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 592cd7fb6f00..773b903c07c1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -861,8 +861,7 @@ static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, str if (ret) /* oops; xprt is already down: */ nfsd4_conn_lost(&conn->cn_xpt_user); - if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN && - conn->cn_flags & NFS4_CDFC4_BACK) { + if (conn->cn_flags & NFS4_CDFC4_BACK) { /* callback channel may be back up */ nfsd4_probe_callback(ses->se_client); } @@ -979,7 +978,6 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); } - nfsd4_probe_callback(clp); return new; } -- cgit v1.2.2 From 0d22f68f02c10d5d10ec5712917e5828b001a822 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 26 Sep 2012 11:36:16 -0400 Subject: nfsd4: don't allow reclaims of expired clients When a confirmed client expires, we normally also need to expire any stable storage record which would allow that client to reclaim state on the next boot. We forgot to do this in some cases. (For example, in destroy_clientid, and in the cases in exchange_id and create_session that destroy and existing confirmed client.) But in most other cases, there's really no harm to calling nfsd4_client_record_remove(), because it is a no-op in the case the client doesn't have an existing The single exception is destroying a client on shutdown, when we want to keep the stable storage records so we can recognize which clients will be allowed to reclaim when we come back up. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 773b903c07c1..412b888faecb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1118,7 +1118,7 @@ unhash_client_locked(struct nfs4_client *clp) } static void -expire_client(struct nfs4_client *clp) +destroy_client(struct nfs4_client *clp) { struct nfs4_openowner *oo; struct nfs4_delegation *dp; @@ -1152,6 +1152,12 @@ expire_client(struct nfs4_client *clp) spin_unlock(&client_lock); } +static void expire_client(struct nfs4_client *clp) +{ + nfsd4_client_record_remove(clp); + destroy_client(clp); +} + static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) { memcpy(target->cl_verifier.data, source->data, @@ -2273,10 +2279,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, unsigned int hash = clientstr_hashval(unconf->cl_recdir); conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); - if (conf) { - nfsd4_client_record_remove(conf); + if (conf) expire_client(conf); - } move_to_confirmed(unconf); nfsd4_probe_callback(unconf); } @@ -3191,7 +3195,6 @@ nfs4_laundromat(void) clp = list_entry(pos, struct nfs4_client, cl_lru); dprintk("NFSD: purging unused client (clientid %08x)\n", clp->cl_clientid.cl_id); - nfsd4_client_record_remove(clp); expire_client(clp); } spin_lock(&recall_lock); @@ -4562,7 +4565,6 @@ void nfsd_forget_clients(u64 num) nfs4_lock_state(); list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { - nfsd4_client_record_remove(clp); expire_client(clp); if (++count == num) break; @@ -4787,11 +4789,11 @@ __nfs4_state_shutdown(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) { while (!list_empty(&conf_id_hashtbl[i])) { clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); - expire_client(clp); + destroy_client(clp); } while (!list_empty(&unconf_str_hashtbl[i])) { clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); - expire_client(clp); + destroy_client(clp); } } INIT_LIST_HEAD(&reaplist); -- cgit v1.2.2 From 616d1ca5d7887dd848f2180218b4c19cb41eb30b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:49:02 +0100 Subject: UAPI: (Scripted) Disintegrate include/linux/nfsd Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones --- include/linux/nfsd/Kbuild | 5 -- include/linux/nfsd/cld.h | 56 ------------------ include/linux/nfsd/debug.h | 31 +--------- include/linux/nfsd/export.h | 52 +---------------- include/linux/nfsd/nfsfh.h | 111 +---------------------------------- include/linux/nfsd/stats.h | 8 +-- include/uapi/linux/nfsd/Kbuild | 5 ++ include/uapi/linux/nfsd/cld.h | 56 ++++++++++++++++++ include/uapi/linux/nfsd/debug.h | 40 +++++++++++++ include/uapi/linux/nfsd/export.h | 58 +++++++++++++++++++ include/uapi/linux/nfsd/nfsfh.h | 122 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/nfsd/stats.h | 17 ++++++ 12 files changed, 302 insertions(+), 259 deletions(-) delete mode 100644 include/linux/nfsd/cld.h create mode 100644 include/uapi/linux/nfsd/cld.h create mode 100644 include/uapi/linux/nfsd/debug.h create mode 100644 include/uapi/linux/nfsd/export.h create mode 100644 include/uapi/linux/nfsd/nfsfh.h create mode 100644 include/uapi/linux/nfsd/stats.h diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild index 5b7d84ac954a..e69de29bb2d1 100644 --- a/include/linux/nfsd/Kbuild +++ b/include/linux/nfsd/Kbuild @@ -1,5 +0,0 @@ -header-y += cld.h -header-y += debug.h -header-y += export.h -header-y += nfsfh.h -header-y += stats.h diff --git a/include/linux/nfsd/cld.h b/include/linux/nfsd/cld.h deleted file mode 100644 index f14a9ab06f1f..000000000000 --- a/include/linux/nfsd/cld.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Upcall description for nfsdcld communication - * - * Copyright (c) 2012 Red Hat, Inc. - * Author(s): Jeff Layton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _NFSD_CLD_H -#define _NFSD_CLD_H - -/* latest upcall version available */ -#define CLD_UPCALL_VERSION 1 - -/* defined by RFC3530 */ -#define NFS4_OPAQUE_LIMIT 1024 - -enum cld_command { - Cld_Create, /* create a record for this cm_id */ - Cld_Remove, /* remove record of this cm_id */ - Cld_Check, /* is this cm_id allowed? */ - Cld_GraceDone, /* grace period is complete */ -}; - -/* representation of long-form NFSv4 client ID */ -struct cld_name { - uint16_t cn_len; /* length of cm_id */ - unsigned char cn_id[NFS4_OPAQUE_LIMIT]; /* client-provided */ -} __attribute__((packed)); - -/* message struct for communication with userspace */ -struct cld_msg { - uint8_t cm_vers; /* upcall version */ - uint8_t cm_cmd; /* upcall command */ - int16_t cm_status; /* return code */ - uint32_t cm_xid; /* transaction id */ - union { - int64_t cm_gracetime; /* grace period start time */ - struct cld_name cm_name; - } __attribute__((packed)) cm_u; -} __attribute__((packed)); - -#endif /* !_NFSD_CLD_H */ diff --git a/include/linux/nfsd/debug.h b/include/linux/nfsd/debug.h index ee4aa91788e7..19ef8375b577 100644 --- a/include/linux/nfsd/debug.h +++ b/include/linux/nfsd/debug.h @@ -5,44 +5,15 @@ * * Copyright (C) 1995 Olaf Kirch */ - #ifndef LINUX_NFSD_DEBUG_H #define LINUX_NFSD_DEBUG_H -#include +#include -/* - * Enable debugging for nfsd. - * Requires RPC_DEBUG. - */ -#ifdef RPC_DEBUG -# define NFSD_DEBUG 1 -#endif - -/* - * knfsd debug flags - */ -#define NFSDDBG_SOCK 0x0001 -#define NFSDDBG_FH 0x0002 -#define NFSDDBG_EXPORT 0x0004 -#define NFSDDBG_SVC 0x0008 -#define NFSDDBG_PROC 0x0010 -#define NFSDDBG_FILEOP 0x0020 -#define NFSDDBG_AUTH 0x0040 -#define NFSDDBG_REPCACHE 0x0080 -#define NFSDDBG_XDR 0x0100 -#define NFSDDBG_LOCKD 0x0200 -#define NFSDDBG_ALL 0x7FFF -#define NFSDDBG_NOCHANGE 0xFFFF - - -#ifdef __KERNEL__ # undef ifdebug # ifdef NFSD_DEBUG # define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag) # else # define ifdebug(flag) if (0) # endif -#endif /* __KERNEL__ */ - #endif /* LINUX_NFSD_DEBUG_H */ diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index e33f747b173c..24c139288db4 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -6,58 +6,11 @@ * * Copyright (C) 1995-1997 Olaf Kirch */ - #ifndef NFSD_EXPORT_H #define NFSD_EXPORT_H -# include -#ifdef __KERNEL__ # include -#endif - -/* - * Important limits for the exports stuff. - */ -#define NFSCLNT_IDMAX 1024 -#define NFSCLNT_ADDRMAX 16 -#define NFSCLNT_KEYMAX 32 - -/* - * Export flags. - */ -#define NFSEXP_READONLY 0x0001 -#define NFSEXP_INSECURE_PORT 0x0002 -#define NFSEXP_ROOTSQUASH 0x0004 -#define NFSEXP_ALLSQUASH 0x0008 -#define NFSEXP_ASYNC 0x0010 -#define NFSEXP_GATHERED_WRITES 0x0020 -/* 40 80 100 currently unused */ -#define NFSEXP_NOHIDE 0x0200 -#define NFSEXP_NOSUBTREECHECK 0x0400 -#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ -#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */ -#define NFSEXP_FSID 0x2000 -#define NFSEXP_CROSSMOUNT 0x4000 -#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ -/* - * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4 - * clients, and only to the single directory that is the root of the - * export; further lookup and readdir operations are treated as if every - * subdirectory was a mountpoint, and ignored if they are not themselves - * exported. This is used by nfsd and mountd to construct the NFSv4 - * pseudofilesystem, which provides access only to paths leading to each - * exported filesystem. - */ -#define NFSEXP_V4ROOT 0x10000 -/* All flags that we claim to support. (Note we don't support NOACL.) */ -#define NFSEXP_ALLFLAGS 0x17E3F - -/* The flags that may vary depending on security flavor: */ -#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ - | NFSEXP_ALLSQUASH \ - | NFSEXP_INSECURE_PORT) - -#ifdef __KERNEL__ +#include /* * FS Locations @@ -154,7 +107,4 @@ static inline void exp_get(struct svc_export *exp) } struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *); -#endif /* __KERNEL__ */ - #endif /* NFSD_EXPORT_H */ - diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index fa63048fecff..a93593f1fa4e 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -10,117 +10,11 @@ * * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ - #ifndef _LINUX_NFSD_FH_H #define _LINUX_NFSD_FH_H -#include -#include -#include -#include -#include -#ifdef __KERNEL__ # include -#endif - -/* - * This is the old "dentry style" Linux NFSv2 file handle. - * - * The xino and xdev fields are currently used to transport the - * ino/dev of the exported inode. - */ -struct nfs_fhbase_old { - __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ - __u32 fb_ino; /* our inode number */ - __u32 fb_dirino; /* dir inode number, 0 for directories */ - __u32 fb_dev; /* our device */ - __u32 fb_xdev; - __u32 fb_xino; - __u32 fb_generation; -}; - -/* - * This is the new flexible, extensible style NFSv2/v3 file handle. - * by Neil Brown - March 2000 - * - * The file handle starts with a sequence of four-byte words. - * The first word contains a version number (1) and three descriptor bytes - * that tell how the remaining 3 variable length fields should be handled. - * These three bytes are auth_type, fsid_type and fileid_type. - * - * All four-byte values are in host-byte-order. - * - * The auth_type field specifies how the filehandle can be authenticated - * This might allow a file to be confirmed to be in a writable part of a - * filetree without checking the path from it up to the root. - * Current values: - * 0 - No authentication. fb_auth is 0 bytes long - * Possible future values: - * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle - * prefixed by a secret and with the important export flags. - * - * The fsid_type identifies how the filesystem (or export point) is - * encoded. - * Current values: - * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number - * NOTE: we cannot use the kdev_t device id value, because kdev_t.h - * says we mustn't. We must break it up and reassemble. - * 1 - 4 byte user specified identifier - * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED - * 3 - 4 byte device id, encoded for user-space, 4 byte inode number - * 4 - 4 byte inode number and 4 byte uuid - * 5 - 8 byte uuid - * 6 - 16 byte uuid - * 7 - 8 byte inode number and 16 byte uuid - * - * The fileid_type identified how the file within the filesystem is encoded. - * This is (will be) passed to, and set by, the underlying filesystem if it supports - * filehandle operations. The filesystem must not use the value '0' or '0xff' and may - * only use the values 1 and 2 as defined below: - * Current values: - * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes. - * 1 - 32bit inode number, 32 bit generation number. - * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number. - * - */ -struct nfs_fhbase_new { - __u8 fb_version; /* == 1, even => nfs_fhbase_old */ - __u8 fb_auth_type; - __u8 fb_fsid_type; - __u8 fb_fileid_type; - __u32 fb_auth[1]; -/* __u32 fb_fsid[0]; floating */ -/* __u32 fb_fileid[0]; floating */ -}; - -struct knfsd_fh { - unsigned int fh_size; /* significant for NFSv3. - * Points to the current size while building - * a new file handle - */ - union { - struct nfs_fhbase_old fh_old; - __u32 fh_pad[NFS4_FHSIZE/4]; - struct nfs_fhbase_new fh_new; - } fh_base; -}; - -#define ofh_dcookie fh_base.fh_old.fb_dcookie -#define ofh_ino fh_base.fh_old.fb_ino -#define ofh_dirino fh_base.fh_old.fb_dirino -#define ofh_dev fh_base.fh_old.fb_dev -#define ofh_xdev fh_base.fh_old.fb_xdev -#define ofh_xino fh_base.fh_old.fb_xino -#define ofh_generation fh_base.fh_old.fb_generation - -#define fh_version fh_base.fh_new.fb_version -#define fh_fsid_type fh_base.fh_new.fb_fsid_type -#define fh_auth_type fh_base.fh_new.fb_auth_type -#define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_auth fh_base.fh_new.fb_auth -#define fh_fsid fh_base.fh_new.fb_auth - -#ifdef __KERNEL__ +#include static inline __u32 ino_t_to_u32(ino_t ino) { @@ -166,7 +60,4 @@ typedef struct svc_fh { } svc_fh; -#endif /* __KERNEL__ */ - - #endif /* _LINUX_NFSD_FH_H */ diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h index 2693ef647df6..e75b2544ff12 100644 --- a/include/linux/nfsd/stats.h +++ b/include/linux/nfsd/stats.h @@ -5,16 +5,11 @@ * * Copyright (C) 1995, 1996 Olaf Kirch */ - #ifndef LINUX_NFSD_STATS_H #define LINUX_NFSD_STATS_H -#include - -/* thread usage wraps very million seconds (approx one fortnight) */ -#define NFSD_USAGE_WRAP (HZ*1000000) +#include -#ifdef __KERNEL__ struct nfsd_stats { unsigned int rchits; /* repcache hits */ @@ -47,5 +42,4 @@ extern struct svc_stat nfsd_svcstats; void nfsd_stat_init(void); void nfsd_stat_shutdown(void); -#endif /* __KERNEL__ */ #endif /* LINUX_NFSD_STATS_H */ diff --git a/include/uapi/linux/nfsd/Kbuild b/include/uapi/linux/nfsd/Kbuild index aafaa5aa54d4..c11bc404053c 100644 --- a/include/uapi/linux/nfsd/Kbuild +++ b/include/uapi/linux/nfsd/Kbuild @@ -1 +1,6 @@ # UAPI Header export list +header-y += cld.h +header-y += debug.h +header-y += export.h +header-y += nfsfh.h +header-y += stats.h diff --git a/include/uapi/linux/nfsd/cld.h b/include/uapi/linux/nfsd/cld.h new file mode 100644 index 000000000000..f14a9ab06f1f --- /dev/null +++ b/include/uapi/linux/nfsd/cld.h @@ -0,0 +1,56 @@ +/* + * Upcall description for nfsdcld communication + * + * Copyright (c) 2012 Red Hat, Inc. + * Author(s): Jeff Layton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _NFSD_CLD_H +#define _NFSD_CLD_H + +/* latest upcall version available */ +#define CLD_UPCALL_VERSION 1 + +/* defined by RFC3530 */ +#define NFS4_OPAQUE_LIMIT 1024 + +enum cld_command { + Cld_Create, /* create a record for this cm_id */ + Cld_Remove, /* remove record of this cm_id */ + Cld_Check, /* is this cm_id allowed? */ + Cld_GraceDone, /* grace period is complete */ +}; + +/* representation of long-form NFSv4 client ID */ +struct cld_name { + uint16_t cn_len; /* length of cm_id */ + unsigned char cn_id[NFS4_OPAQUE_LIMIT]; /* client-provided */ +} __attribute__((packed)); + +/* message struct for communication with userspace */ +struct cld_msg { + uint8_t cm_vers; /* upcall version */ + uint8_t cm_cmd; /* upcall command */ + int16_t cm_status; /* return code */ + uint32_t cm_xid; /* transaction id */ + union { + int64_t cm_gracetime; /* grace period start time */ + struct cld_name cm_name; + } __attribute__((packed)) cm_u; +} __attribute__((packed)); + +#endif /* !_NFSD_CLD_H */ diff --git a/include/uapi/linux/nfsd/debug.h b/include/uapi/linux/nfsd/debug.h new file mode 100644 index 000000000000..a6f453c740b8 --- /dev/null +++ b/include/uapi/linux/nfsd/debug.h @@ -0,0 +1,40 @@ +/* + * linux/include/linux/nfsd/debug.h + * + * Debugging-related stuff for nfsd + * + * Copyright (C) 1995 Olaf Kirch + */ + +#ifndef _UAPILINUX_NFSD_DEBUG_H +#define _UAPILINUX_NFSD_DEBUG_H + +#include + +/* + * Enable debugging for nfsd. + * Requires RPC_DEBUG. + */ +#ifdef RPC_DEBUG +# define NFSD_DEBUG 1 +#endif + +/* + * knfsd debug flags + */ +#define NFSDDBG_SOCK 0x0001 +#define NFSDDBG_FH 0x0002 +#define NFSDDBG_EXPORT 0x0004 +#define NFSDDBG_SVC 0x0008 +#define NFSDDBG_PROC 0x0010 +#define NFSDDBG_FILEOP 0x0020 +#define NFSDDBG_AUTH 0x0040 +#define NFSDDBG_REPCACHE 0x0080 +#define NFSDDBG_XDR 0x0100 +#define NFSDDBG_LOCKD 0x0200 +#define NFSDDBG_ALL 0x7FFF +#define NFSDDBG_NOCHANGE 0xFFFF + + + +#endif /* _UAPILINUX_NFSD_DEBUG_H */ diff --git a/include/uapi/linux/nfsd/export.h b/include/uapi/linux/nfsd/export.h new file mode 100644 index 000000000000..cf47c313794e --- /dev/null +++ b/include/uapi/linux/nfsd/export.h @@ -0,0 +1,58 @@ +/* + * include/linux/nfsd/export.h + * + * Public declarations for NFS exports. The definitions for the + * syscall interface are in nfsctl.h + * + * Copyright (C) 1995-1997 Olaf Kirch + */ + +#ifndef _UAPINFSD_EXPORT_H +#define _UAPINFSD_EXPORT_H + +# include + +/* + * Important limits for the exports stuff. + */ +#define NFSCLNT_IDMAX 1024 +#define NFSCLNT_ADDRMAX 16 +#define NFSCLNT_KEYMAX 32 + +/* + * Export flags. + */ +#define NFSEXP_READONLY 0x0001 +#define NFSEXP_INSECURE_PORT 0x0002 +#define NFSEXP_ROOTSQUASH 0x0004 +#define NFSEXP_ALLSQUASH 0x0008 +#define NFSEXP_ASYNC 0x0010 +#define NFSEXP_GATHERED_WRITES 0x0020 +/* 40 80 100 currently unused */ +#define NFSEXP_NOHIDE 0x0200 +#define NFSEXP_NOSUBTREECHECK 0x0400 +#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ +#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */ +#define NFSEXP_FSID 0x2000 +#define NFSEXP_CROSSMOUNT 0x4000 +#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ +/* + * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4 + * clients, and only to the single directory that is the root of the + * export; further lookup and readdir operations are treated as if every + * subdirectory was a mountpoint, and ignored if they are not themselves + * exported. This is used by nfsd and mountd to construct the NFSv4 + * pseudofilesystem, which provides access only to paths leading to each + * exported filesystem. + */ +#define NFSEXP_V4ROOT 0x10000 +/* All flags that we claim to support. (Note we don't support NOACL.) */ +#define NFSEXP_ALLFLAGS 0x17E3F + +/* The flags that may vary depending on security flavor: */ +#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ + | NFSEXP_ALLSQUASH \ + | NFSEXP_INSECURE_PORT) + + +#endif /* _UAPINFSD_EXPORT_H */ diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h new file mode 100644 index 000000000000..616e3b396476 --- /dev/null +++ b/include/uapi/linux/nfsd/nfsfh.h @@ -0,0 +1,122 @@ +/* + * include/linux/nfsd/nfsfh.h + * + * This file describes the layout of the file handles as passed + * over the wire. + * + * Earlier versions of knfsd used to sign file handles using keyed MD5 + * or SHA. I've removed this code, because it doesn't give you more + * security than blocking external access to port 2049 on your firewall. + * + * Copyright (C) 1995, 1996, 1997 Olaf Kirch + */ + +#ifndef _UAPI_LINUX_NFSD_FH_H +#define _UAPI_LINUX_NFSD_FH_H + +#include +#include +#include +#include +#include + +/* + * This is the old "dentry style" Linux NFSv2 file handle. + * + * The xino and xdev fields are currently used to transport the + * ino/dev of the exported inode. + */ +struct nfs_fhbase_old { + __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ + __u32 fb_ino; /* our inode number */ + __u32 fb_dirino; /* dir inode number, 0 for directories */ + __u32 fb_dev; /* our device */ + __u32 fb_xdev; + __u32 fb_xino; + __u32 fb_generation; +}; + +/* + * This is the new flexible, extensible style NFSv2/v3 file handle. + * by Neil Brown - March 2000 + * + * The file handle starts with a sequence of four-byte words. + * The first word contains a version number (1) and three descriptor bytes + * that tell how the remaining 3 variable length fields should be handled. + * These three bytes are auth_type, fsid_type and fileid_type. + * + * All four-byte values are in host-byte-order. + * + * The auth_type field specifies how the filehandle can be authenticated + * This might allow a file to be confirmed to be in a writable part of a + * filetree without checking the path from it up to the root. + * Current values: + * 0 - No authentication. fb_auth is 0 bytes long + * Possible future values: + * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle + * prefixed by a secret and with the important export flags. + * + * The fsid_type identifies how the filesystem (or export point) is + * encoded. + * Current values: + * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number + * NOTE: we cannot use the kdev_t device id value, because kdev_t.h + * says we mustn't. We must break it up and reassemble. + * 1 - 4 byte user specified identifier + * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED + * 3 - 4 byte device id, encoded for user-space, 4 byte inode number + * 4 - 4 byte inode number and 4 byte uuid + * 5 - 8 byte uuid + * 6 - 16 byte uuid + * 7 - 8 byte inode number and 16 byte uuid + * + * The fileid_type identified how the file within the filesystem is encoded. + * This is (will be) passed to, and set by, the underlying filesystem if it supports + * filehandle operations. The filesystem must not use the value '0' or '0xff' and may + * only use the values 1 and 2 as defined below: + * Current values: + * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes. + * 1 - 32bit inode number, 32 bit generation number. + * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number. + * + */ +struct nfs_fhbase_new { + __u8 fb_version; /* == 1, even => nfs_fhbase_old */ + __u8 fb_auth_type; + __u8 fb_fsid_type; + __u8 fb_fileid_type; + __u32 fb_auth[1]; +/* __u32 fb_fsid[0]; floating */ +/* __u32 fb_fileid[0]; floating */ +}; + +struct knfsd_fh { + unsigned int fh_size; /* significant for NFSv3. + * Points to the current size while building + * a new file handle + */ + union { + struct nfs_fhbase_old fh_old; + __u32 fh_pad[NFS4_FHSIZE/4]; + struct nfs_fhbase_new fh_new; + } fh_base; +}; + +#define ofh_dcookie fh_base.fh_old.fb_dcookie +#define ofh_ino fh_base.fh_old.fb_ino +#define ofh_dirino fh_base.fh_old.fb_dirino +#define ofh_dev fh_base.fh_old.fb_dev +#define ofh_xdev fh_base.fh_old.fb_xdev +#define ofh_xino fh_base.fh_old.fb_xino +#define ofh_generation fh_base.fh_old.fb_generation + +#define fh_version fh_base.fh_new.fb_version +#define fh_fsid_type fh_base.fh_new.fb_fsid_type +#define fh_auth_type fh_base.fh_new.fb_auth_type +#define fh_fileid_type fh_base.fh_new.fb_fileid_type +#define fh_auth fh_base.fh_new.fb_auth +#define fh_fsid fh_base.fh_new.fb_auth + + + +#endif /* _UAPI_LINUX_NFSD_FH_H */ diff --git a/include/uapi/linux/nfsd/stats.h b/include/uapi/linux/nfsd/stats.h new file mode 100644 index 000000000000..9fb7a0644263 --- /dev/null +++ b/include/uapi/linux/nfsd/stats.h @@ -0,0 +1,17 @@ +/* + * linux/include/linux/nfsd/stats.h + * + * Statistics for NFS server. + * + * Copyright (C) 1995, 1996 Olaf Kirch + */ + +#ifndef _UAPILINUX_NFSD_STATS_H +#define _UAPILINUX_NFSD_STATS_H + +#include + +/* thread usage wraps very million seconds (approx one fortnight) */ +#define NFSD_USAGE_WRAP (HZ*1000000) + +#endif /* _UAPILINUX_NFSD_STATS_H */ -- cgit v1.2.2 From e3dd9a52cb5552c46c2a4ca7ccdfb4dab5c72457 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:49:04 +0100 Subject: UAPI: (Scripted) Disintegrate include/linux/sunrpc Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones --- include/linux/sunrpc/Kbuild | 1 - include/linux/sunrpc/debug.h | 39 +------------------------------ include/uapi/linux/sunrpc/Kbuild | 1 + include/uapi/linux/sunrpc/debug.h | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 39 deletions(-) create mode 100644 include/uapi/linux/sunrpc/debug.h diff --git a/include/linux/sunrpc/Kbuild b/include/linux/sunrpc/Kbuild index 98df21164a86..e69de29bb2d1 100644 --- a/include/linux/sunrpc/Kbuild +++ b/include/linux/sunrpc/Kbuild @@ -1 +0,0 @@ -header-y += debug.h diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index a76cc20d98ce..9385bd74c860 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -5,28 +5,11 @@ * * Copyright (C) 1996, Olaf Kirch */ - #ifndef _LINUX_SUNRPC_DEBUG_H_ #define _LINUX_SUNRPC_DEBUG_H_ -/* - * RPC debug facilities - */ -#define RPCDBG_XPRT 0x0001 -#define RPCDBG_CALL 0x0002 -#define RPCDBG_DEBUG 0x0004 -#define RPCDBG_NFS 0x0008 -#define RPCDBG_AUTH 0x0010 -#define RPCDBG_BIND 0x0020 -#define RPCDBG_SCHED 0x0040 -#define RPCDBG_TRANS 0x0080 -#define RPCDBG_SVCXPRT 0x0100 -#define RPCDBG_SVCDSP 0x0200 -#define RPCDBG_MISC 0x0400 -#define RPCDBG_CACHE 0x0800 -#define RPCDBG_ALL 0x7fff +#include -#ifdef __KERNEL__ /* * Enable RPC debugging/profiling. @@ -87,24 +70,4 @@ void rpc_register_sysctl(void); void rpc_unregister_sysctl(void); #endif -#endif /* __KERNEL__ */ - -/* - * Declarations for the sysctl debug interface, which allows to read or - * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc - * module currently registers its sysctl table dynamically, the sysctl path - * for module FOO is . - */ - -enum { - CTL_RPCDEBUG = 1, - CTL_NFSDEBUG, - CTL_NFSDDEBUG, - CTL_NLMDEBUG, - CTL_SLOTTABLE_UDP, - CTL_SLOTTABLE_TCP, - CTL_MIN_RESVPORT, - CTL_MAX_RESVPORT, -}; - #endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff --git a/include/uapi/linux/sunrpc/Kbuild b/include/uapi/linux/sunrpc/Kbuild index aafaa5aa54d4..8e02e47c20fb 100644 --- a/include/uapi/linux/sunrpc/Kbuild +++ b/include/uapi/linux/sunrpc/Kbuild @@ -1 +1,2 @@ # UAPI Header export list +header-y += debug.h diff --git a/include/uapi/linux/sunrpc/debug.h b/include/uapi/linux/sunrpc/debug.h new file mode 100644 index 000000000000..830e34493a8c --- /dev/null +++ b/include/uapi/linux/sunrpc/debug.h @@ -0,0 +1,48 @@ +/* + * linux/include/linux/sunrpc/debug.h + * + * Debugging support for sunrpc module + * + * Copyright (C) 1996, Olaf Kirch + */ + +#ifndef _UAPI_LINUX_SUNRPC_DEBUG_H_ +#define _UAPI_LINUX_SUNRPC_DEBUG_H_ + +/* + * RPC debug facilities + */ +#define RPCDBG_XPRT 0x0001 +#define RPCDBG_CALL 0x0002 +#define RPCDBG_DEBUG 0x0004 +#define RPCDBG_NFS 0x0008 +#define RPCDBG_AUTH 0x0010 +#define RPCDBG_BIND 0x0020 +#define RPCDBG_SCHED 0x0040 +#define RPCDBG_TRANS 0x0080 +#define RPCDBG_SVCXPRT 0x0100 +#define RPCDBG_SVCDSP 0x0200 +#define RPCDBG_MISC 0x0400 +#define RPCDBG_CACHE 0x0800 +#define RPCDBG_ALL 0x7fff + + +/* + * Declarations for the sysctl debug interface, which allows to read or + * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc + * module currently registers its sysctl table dynamically, the sysctl path + * for module FOO is . + */ + +enum { + CTL_RPCDEBUG = 1, + CTL_NFSDEBUG, + CTL_NFSDDEBUG, + CTL_NLMDEBUG, + CTL_SLOTTABLE_UDP, + CTL_SLOTTABLE_TCP, + CTL_MIN_RESVPORT, + CTL_MAX_RESVPORT, +}; + +#endif /* _UAPI_LINUX_SUNRPC_DEBUG_H_ */ -- cgit v1.2.2