From 2411967305dbfb8930b9b9c11f55f6c1ef7361e1 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Thu, 24 May 2012 15:42:17 -0400 Subject: nfsd: probe the back channel on new connections Initiate a CB probe when a new connection with the correct direction is added to a session (IFF backchannel is marked as down). Without this a BIND_CONN_TO_SESSION has no effect on the internal backchannel state, which causes the server to reply to every SEQUENCE op with the SEQ4_STATUS_CB_PATH_DOWN flag set until DESTROY_SESSION. Signed-off-by: Weston Andros Adamson Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 94effd5bc4a1..8b80a10d4fc5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -862,6 +862,11 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, if (ret) /* 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) { + /* callback channel may be back up */ + nfsd4_probe_callback(ses->se_client); + } return nfs_ok; } -- cgit v1.2.3 From 7df302f75ee28a6a87436e93b625ef60d37d098e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 29 May 2012 13:56:37 -0400 Subject: NFSD: TEST_STATEID should not return NFS4ERR_STALE_STATEID According to RFC 5661, the TEST_STATEID operation is not allowed to return NFS4ERR_STALE_STATEID. In addition, RFC 5661 says: 15.1.16.5. NFS4ERR_STALE_STATEID (Error Code 10023) A stateid generated by an earlier server instance was used. This error is moot in NFSv4.1 because all operations that take a stateid MUST be preceded by the SEQUENCE operation, and the earlier server instance is detected by the session infrastructure that supports SEQUENCE. I triggered NFS4ERR_STALE_STATEID while testing the Linux client's NOGRACE recovery. Bruce suggested an additional test that could be useful to client developers. Lastly, RFC 5661, section 18.48.3 has this: o Special stateids are always considered invalid (they result in the error code NFS4ERR_BAD_STATEID). An explicit check is made for those state IDs to avoid printk noise. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 22 ++++++++++++++++------ fs/nfsd/state.h | 1 - 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8b80a10d4fc5..59b9efc9d69b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include "xdr4.h" @@ -3338,18 +3339,26 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s return nfserr_old_stateid; } -__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) +static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) { struct nfs4_stid *s; struct nfs4_ol_stateid *ols; __be32 status; - if (STALE_STATEID(stateid)) - return nfserr_stale_stateid; - + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) + return nfserr_bad_stateid; + /* Client debugging aid. */ + if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { + char addr_str[INET6_ADDRSTRLEN]; + rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, + sizeof(addr_str)); + pr_warn_ratelimited("NFSD: client %s testing state ID " + "with incorrect client ID\n", addr_str); + return nfserr_bad_stateid; + } s = find_stateid(cl, stateid); if (!s) - return nfserr_stale_stateid; + return nfserr_bad_stateid; status = check_stateid_generation(stateid, &s->sc_stateid, 1); if (status) return status; @@ -3468,7 +3477,8 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) - stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid); + stateid->ts_id_status = + nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); nfs4_unlock_state(); return nfs_ok; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 849091e16ea6..495df4e3aa67 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -475,7 +475,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern int nfs4_client_to_reclaim(const char *name); extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); extern void release_session_client(struct nfsd4_session *); -extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); /* nfs4recover operations */ -- cgit v1.2.3 From 9068bed1a35da413df8751b8b1b845a04f62b9fd Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 5 Jun 2012 16:29:06 -0400 Subject: nfsd4: remove unnecessary comment For the most part readers of cl_cb_state only need a value that is "eventually" right. And the value is set only either 1) in response to some change of state, in which case it's set to UNKNOWN and then a callback rpc is sent to probe the real state, or b) in the handling of a response to such a callback. UNKNOWN is therefore always a "temporary" state, and for the other states we're happy to accept last writer wins. So I think we're OK here. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index a5fd6b982f27..cbaf4f8bb7b7 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -756,7 +756,6 @@ static void do_probe_callback(struct nfs4_client *clp) */ void nfsd4_probe_callback(struct nfs4_client *clp) { - /* XXX: atomicity? Also, should we be using cl_flags? */ clp->cl_cb_state = NFSD4_CB_UNKNOWN; set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); do_probe_callback(clp); -- cgit v1.2.3 From e1aaa8916f19d23d39d88e985bc6933a74159e91 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 6 Jun 2012 16:01:37 -0400 Subject: nfsd4: nfsd4_lock() cleanup Share a little common logic. And note the comments here are a little out of date (e.g. we don't always create new state in the "new" case any more.) Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 59b9efc9d69b..de8f7e45102d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4059,11 +4059,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); if (lock->lk_is_new) { - /* - * Client indicates that this is a new lockowner. - * Use open owner and open stateid to create lock owner and - * lock stateid. - */ struct nfs4_ol_stateid *open_stp = NULL; if (nfsd4_has_session(cstate)) @@ -4090,17 +4085,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; status = lookup_or_create_lock_state(cstate, open_stp, lock, &lock_stp, &new_state); - if (status) - goto out; - } else { - /* lock (lock owner + lock stateid) already exists */ + } else status = nfs4_preprocess_seqid_op(cstate, lock->lk_old_lock_seqid, &lock->lk_old_lock_stateid, NFS4_LOCK_STID, &lock_stp); - if (status) - goto out; - } + if (status) + goto out; lock_sop = lockowner(lock_stp->st_stateowner); lkflg = setlkflg(lock->lk_type); -- cgit v1.2.3 From 4af825041b06c2ef9b5933288267a11e029eb360 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 7 Jun 2012 17:30:45 -0400 Subject: nfsd4: process_open2 cleanup Note we can simplify the error handling a little by doing the truncate earlier. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index de8f7e45102d..9efa4055b5a8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3011,16 +3011,14 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf goto out; } else { status = nfs4_get_vfs_file(rqstp, fp, current_fh, open); + if (status) + goto out; + status = nfsd4_truncate(rqstp, current_fh, open); if (status) goto out; stp = open->op_stp; open->op_stp = NULL; init_open_stateid(stp, fp, open); - status = nfsd4_truncate(rqstp, current_fh, open); - if (status) { - release_open_stateid(stp); - goto out; - } } update_stateid(&stp->st_stid.sc_stateid); memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); -- cgit v1.2.3 From 2930d381d22b9c56f40dd4c63a8fa59719ca2c3c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 5 Jun 2012 16:52:06 -0400 Subject: nfsd4: our filesystems are normally case sensitive Actually, xfs and jfs can optionally be case insensitive; we'll handle that case in later patches. Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4949667c84ea..6322df36031f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2259,7 +2259,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(1); + WRITE32(0); } if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { if ((buflen -= 4) < 0) -- cgit v1.2.3 From 74dbafaf5d84b5187e50dbe82442ec8df66d55b3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 6 Jun 2012 12:53:48 -0400 Subject: nfsd4: release openowners on free in >=4.1 case We don't need to keep openowners around in the >=4.1 case, because they aren't needed to handle CLOSE replays any more (that's a problem for sessions). And doing so causes unexpected failures on a subsequent destroy_clientid to fail. We probably also need something comparable for lock owners on last unlock. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9efa4055b5a8..e404fca08260 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3763,12 +3763,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_close_open_stateid(stp); oo->oo_last_closed_stid = stp; - /* place unused nfs4_stateowners on so_close_lru list to be - * released by the laundromat service after the lease period - * to enable us to handle CLOSE replay - */ - if (list_empty(&oo->oo_owner.so_stateids)) - move_to_close_lru(oo); + if (list_empty(&oo->oo_owner.so_stateids)) { + if (cstate->minorversion) { + release_openowner(oo); + cstate->replay_owner = NULL; + } else { + /* + * In the 4.0 case we need to keep the owners around a + * little while to handle CLOSE replay. + */ + if (list_empty(&oo->oo_owner.so_stateids)) + move_to_close_lru(oo); + } + } out: if (!cstate->replay_owner) nfs4_unlock_state(); -- cgit v1.2.3 From d91d0b569044ab366895d587d4811b154dd7d7f5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 6 Jun 2012 12:12:57 -0400 Subject: nfsd: allow owner_override only for regular files We normally allow the owner of a file to override permissions checks on IO operations, since: - the client will take responsibility for doing an access check on open; - the permission checks offer no protection against malicious clients--if they can authenticate as the file's owner then they can always just change its permissions; - checking permission on each IO operation breaks the usual posix rule that permission is checked only on open. However, we've never allowed the owner to override permissions on readdir operations, even though the above logic would also apply to directories. I've never heard of this causing a problem, probably because a) simultaneously opening and creating a directory (with restricted mode) isn't possible, and b) opening a directory, then chmod'ing it, is rare. Our disallowal of owner-override on directories appears to be an accident, though--the readdir itself succeeds, and then we fail just because lookup_one_len() calls in our filldir methods fail. I'm not sure what the easiest fix for that would be. For now, just make this behavior obvious by denying the override right at the start. This also fixes some odd v4 behavior: with the rdattr_error attribute requested, it would perform the readdir but return an ACCES error with each entry. Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c8bd9c3be7f7..3256b5c324bc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -757,8 +757,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, * If we get here, then the client has already done an "open", * and (hopefully) checked permission - so allow OWNER_OVERRIDE * in case a chmod has now revoked permission. + * + * Arguably we should also allow the owner override for + * directories, but we never have and it doesn't seem to have + * caused anyone a problem. If we were to change this, note + * also that our filldir callbacks would need a variant of + * lookup_one_len that doesn't check permissions. */ - err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE); + if (type == S_IFREG) + may_flags |= NFSD_MAY_OWNER_OVERRIDE; + err = fh_verify(rqstp, fhp, type, may_flags); if (err) goto out; -- cgit v1.2.3 From 7f2e7dc0fdd9f124da43d1bd12adcebf92bedf16 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 12 Jun 2012 16:06:29 -0400 Subject: nfsd: share some function prototypes Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsd.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 1671429ffa66..6d425c2f9fcd 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -72,6 +72,8 @@ int nfsd_nrthreads(void); int nfsd_nrpools(void); int nfsd_get_nrthreads(int n, int *); int nfsd_set_nrthreads(int n, int *); +int nfsd_pool_stats_open(struct inode *, struct file *); +int nfsd_pool_stats_release(struct inode *, struct file *); #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #ifdef CONFIG_NFSD_V2_ACL -- cgit v1.2.3 From 5559b50acdcdcad7e362882d3261bf934c9436f6 Mon Sep 17 00:00:00 2001 From: Vivek Trivedi Date: Tue, 24 Jul 2012 21:18:20 +0530 Subject: nfsd4: fix cr_principal comparison check in same_creds This fixes a wrong check for same cr_principal in same_creds Introduced by 8fbba96e5b327665265ad02b7f331b68536828bf "nfsd4: stricter cred comparison for setclientid/exchange_id". Cc: stable@vger.kernel.org Signed-off-by: Vivek Trivedi Signed-off-by: Namjae Jeon Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e404fca08260..fe96015fbfcb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1221,7 +1221,7 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2) return true; } -static int +static bool same_creds(struct svc_cred *cr1, struct svc_cred *cr2) { if ((cr1->cr_flavor != cr2->cr_flavor) @@ -1233,7 +1233,7 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) return true; if (!cr1->cr_principal || !cr2->cr_principal) return false; - return 0 == strcmp(cr1->cr_principal, cr1->cr_principal); + return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); } static void gen_clid(struct nfs4_client *clp) -- cgit v1.2.3 From a6d88f293ecd1b7444e128777f4a893e7a998852 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 25 May 2012 18:38:50 +0400 Subject: NFSd: fix locking in nfsd_forget_delegations() This patch adds recall_lock hold to nfsd_forget_delegations() to protect nfsd_process_n_delegations() call. Also, looks like it would be better to collect delegations to some local on-stack list, and then unhash collected list. This split allows to simplify locking, because delegation traversing is protected by recall_lock, when delegation unhash is protected by client_mutex. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fe96015fbfcb..d10ad8bc47aa 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4575,7 +4575,7 @@ void nfsd_forget_openowners(u64 num) printk(KERN_INFO "NFSD: Forgot %d open owners", count); } -int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *)) +int nfsd_process_n_delegations(u64 num, struct list_head *list) { int i, count = 0; struct nfs4_file *fp, *fnext; @@ -4584,7 +4584,7 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio for (i = 0; i < FILE_HASH_SIZE; i++) { list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { - deleg_func(dp); + list_move(&dp->dl_recall_lru, list); if (++count == num) return count; } @@ -4597,9 +4597,16 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio void nfsd_forget_delegations(u64 num) { unsigned int count; + LIST_HEAD(victims); + struct nfs4_delegation *dp, *dnext; + + spin_lock(&recall_lock); + count = nfsd_process_n_delegations(num, &victims); + spin_unlock(&recall_lock); nfs4_lock_state(); - count = nfsd_process_n_delegations(num, unhash_delegation); + list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) + unhash_delegation(dp); nfs4_unlock_state(); printk(KERN_INFO "NFSD: Forgot %d delegations", count); @@ -4608,12 +4615,16 @@ void nfsd_forget_delegations(u64 num) void nfsd_recall_delegations(u64 num) { unsigned int count; + LIST_HEAD(victims); + struct nfs4_delegation *dp, *dnext; - nfs4_lock_state(); spin_lock(&recall_lock); - count = nfsd_process_n_delegations(num, nfsd_break_one_deleg); + count = nfsd_process_n_delegations(num, &victims); + list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) { + list_del(&dp->dl_recall_lru); + nfsd_break_one_deleg(dp); + } spin_unlock(&recall_lock); - nfs4_unlock_state(); printk(KERN_INFO "NFSD: Recalled %d delegations", count); } -- cgit v1.2.3 From a007c4c3e943ecc054a806c259d95420a188754b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 12 Jun 2012 16:54:16 -0400 Subject: nfsd: add get_uint for u32's I don't think there's a practical difference for the range of values these interfaces should see, but it would be safer to be unambiguous. Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 6 +++--- include/linux/sunrpc/cache.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index ba233499b9a5..1114463bb856 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -398,7 +398,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) int migrated, i, err; /* listsize */ - err = get_int(mesg, &fsloc->locations_count); + err = get_uint(mesg, &fsloc->locations_count); if (err) return err; if (fsloc->locations_count > MAX_FS_LOCATIONS) @@ -456,7 +456,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) return -EINVAL; for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) { - err = get_int(mesg, &f->pseudoflavor); + err = get_uint(mesg, &f->pseudoflavor); if (err) return err; /* @@ -465,7 +465,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) * problem at export time instead of when a client fails * to authenticate. */ - err = get_int(mesg, &f->flags); + err = get_uint(mesg, &f->flags); if (err) return err; /* Only some flags are allowed to differ between flavors: */ diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index af42596a82f9..f792794f6634 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -230,6 +230,22 @@ static inline int get_int(char **bpp, int *anint) return 0; } +static inline int get_uint(char **bpp, unsigned int *anint) +{ + char buf[50]; + int len = qword_get(bpp, buf, sizeof(buf)); + + if (len < 0) + return -EINVAL; + if (len == 0) + return -ENOENT; + + if (kstrtouint(buf, 0, anint)) + return -EINVAL; + + return 0; +} + /* * timestamps kept in the cache are expressed in seconds * since boot. This is the best for measuring differences in -- cgit v1.2.3 From 19f7e2ca44dfc3c1b3f499fc46801f98d403500f Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 3 Jul 2012 16:46:41 +0400 Subject: NFSd: introduce nfsd_destroy() helper Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsctl.c | 8 ++------ fs/nfsd/nfsd.h | 9 +++++++++ fs/nfsd/nfssvc.c | 14 +++----------- 3 files changed, 14 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c55298ed5772..fa49cff5ee65 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -673,9 +673,7 @@ static ssize_t __write_ports_addfd(char *buf) err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); if (err < 0) { - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); return err; } @@ -744,9 +742,7 @@ out_close: svc_xprt_put(xprt); } out_err: - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); return err; } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 6d425c2f9fcd..7b248a24d5c5 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -75,6 +75,15 @@ int nfsd_set_nrthreads(int n, int *); int nfsd_pool_stats_open(struct inode *, struct file *); int nfsd_pool_stats_release(struct inode *, struct file *); +static inline void nfsd_destroy(struct net *net) +{ + int destroy = (nfsd_serv->sv_nrthreads == 1); + + if (destroy) + svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); +} + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #ifdef CONFIG_NFSD_V2_ACL extern struct svc_version nfsd_acl_version2; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ee709fc8f58b..8621e36ce8dd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -427,11 +427,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) if (err) break; } - - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); - + nfsd_destroy(net); return err; } @@ -478,9 +474,7 @@ out_shutdown: if (error < 0 && !nfsd_up_before) nfsd_shutdown(); out_destroy: - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); /* Release server */ + nfsd_destroy(net); /* Release server */ out: mutex_unlock(&nfsd_mutex); return error; @@ -682,9 +676,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file) mutex_lock(&nfsd_mutex); /* this function really, really should have been called svc_put() */ - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); mutex_unlock(&nfsd_mutex); return ret; } -- cgit v1.2.3 From 57c8b13e3cd0f94944c9691ce7f58e5fcef8a12d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 3 Jul 2012 16:46:41 +0400 Subject: NFSd: set nfsd_serv to NULL after service destruction In nfsd_destroy(): if (destroy) svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_server); svc_shutdown_net(nfsd_serv, net) calls nfsd_last_thread(), which sets nfsd_serv to NULL, causing a NULL dereference on the following line. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsd.h | 2 ++ fs/nfsd/nfssvc.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 7b248a24d5c5..2244222368ab 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -82,6 +82,8 @@ static inline void nfsd_destroy(struct net *net) if (destroy) svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); + if (destroy) + nfsd_serv = NULL; } #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 8621e36ce8dd..240473cb708f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -254,8 +254,6 @@ static void nfsd_shutdown(void) static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { - /* When last nfsd thread exits we need to do some clean-up */ - nfsd_serv = NULL; nfsd_shutdown(); svc_rpcb_cleanup(serv, net); @@ -332,6 +330,7 @@ static int nfsd_get_default_max_blksize(void) int nfsd_create_serv(void) { int error; + struct net *net = current->nsproxy->net_ns; WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { @@ -346,7 +345,7 @@ int nfsd_create_serv(void) if (nfsd_serv == NULL) return -ENOMEM; - error = svc_bind(nfsd_serv, current->nsproxy->net_ns); + error = svc_bind(nfsd_serv, net); if (error < 0) { svc_destroy(nfsd_serv); return error; @@ -557,12 +556,13 @@ nfsd(void *vrqstp) nfsdstats.th_cnt --; out: - if (rqstp->rq_server->sv_nrthreads == 1) - svc_shutdown_net(rqstp->rq_server, &init_net); + rqstp->rq_server = NULL; /* Release the thread */ svc_exit_thread(rqstp); + nfsd_destroy(&init_net); + /* Release module */ mutex_unlock(&nfsd_mutex); module_put_and_exit(0); -- cgit v1.2.3 From 3b6e2723f32de42028617f2c99b244ccd72cd959 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Fri, 27 Jul 2012 00:42:52 -0400 Subject: locks: prevent side-effects of locks_release_private before file_lock is initialized When calling fcntl(fd, F_SETLEASE, lck) [with lck=F_WRLCK or F_RDLCK], the custom signal or owner (if any were previously set using F_SETSIG or F_SETOWN fcntls) would be reset when F_SETLEASE was called for the second time on the same file descriptor. This bug is a regression of 2.6.37 and is described here: https://bugzilla.kernel.org/show_bug.cgi?id=43336 This patch reverts a commit from Oct 2004 (with subject "nfs4 lease: move the f_delown processing") which originally introduced the lm_release_private callback. Signed-off-by: Filipe Brandenburger Signed-off-by: J. Bruce Fields --- fs/locks.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 814c51d0de47..86668dd211ae 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -427,18 +427,8 @@ static void lease_break_callback(struct file_lock *fl) kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); } -static void lease_release_private_callback(struct file_lock *fl) -{ - if (!fl->fl_file) - return; - - f_delown(fl->fl_file); - fl->fl_file->f_owner.signum = 0; -} - static const struct lock_manager_operations lease_manager_ops = { .lm_break = lease_break_callback, - .lm_release_private = lease_release_private_callback, .lm_change = lease_modify, }; @@ -1155,8 +1145,13 @@ int lease_modify(struct file_lock **before, int arg) return error; lease_clear_pending(fl, arg); locks_wake_up_blocks(fl); - if (arg == F_UNLCK) + if (arg == F_UNLCK) { + struct file *filp = fl->fl_file; + + f_delown(filp); + filp->f_owner.signum = 0; locks_delete_lock(before); + } return 0; } -- cgit v1.2.3 From 96d6d59ceaeaacba4088862f3c57fcd011f52832 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 16:18:00 -0400 Subject: locks: move lease-specific code out of locks_delete_lock No point putting something only used by one caller into common code. Signed-off-by: J. Bruce Fields --- fs/locks.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 86668dd211ae..541075a41527 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -570,12 +570,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p) fl->fl_next = NULL; list_del_init(&fl->fl_link); - fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); - if (fl->fl_fasync != NULL) { - printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); - fl->fl_fasync = NULL; - } - if (fl->fl_nspid) { put_pid(fl->fl_nspid); fl->fl_nspid = NULL; @@ -1150,6 +1144,11 @@ int lease_modify(struct file_lock **before, int arg) f_delown(filp); filp->f_owner.signum = 0; + fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); + if (fl->fl_fasync != NULL) { + printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); + fl->fl_fasync = NULL; + } locks_delete_lock(before); } return 0; -- cgit v1.2.3 From 99dbb8fe0992ecefd061e5efa7604b92eab58ccc Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 16:30:12 -0400 Subject: nfsd4: fix missing fault_inject.h include Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d10ad8bc47aa..fddb18b2e877 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -44,6 +44,7 @@ #include "xdr4.h" #include "vfs.h" #include "current_stateid.h" +#include "fault_inject.h" #define NFSDDBG_FACILITY NFSDDBG_PROC -- cgit v1.2.3 From b26411f85d3763ec5fc553854d9c3c0966072090 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:55:54 +0400 Subject: LockD: mark host per network namespace on garbage collect This is required for per-network NLM shutdown and cleanup. This patch passes init_net for a while. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 3 ++- fs/lockd/svcsubs.c | 19 +++++++++++++------ include/linux/lockd/lockd.h | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index eb75ca7c2d6e..2c5f41b098e9 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -628,13 +628,14 @@ nlm_gc_hosts(void) struct hlist_head *chain; struct hlist_node *pos, *next; struct nlm_host *host; + struct net *net = &init_net; dprintk("lockd: host garbage collection\n"); for_each_host(host, pos, chain, nlm_server_hosts) host->h_inuse = 0; /* Mark all hosts that hold locks, blocks or shares */ - nlmsvc_mark_resources(); + nlmsvc_mark_resources(net); for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { if (atomic_read(&host->h_count) || host->h_inuse diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 2240d384d787..0deb5f6c9dd4 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -309,7 +309,8 @@ nlm_release_file(struct nlm_file *file) * Helpers function for resource traversal * * nlmsvc_mark_host: - * used by the garbage collector; simply sets h_inuse. + * used by the garbage collector; simply sets h_inuse only for those + * hosts, which passed network check. * Always returns 0. * * nlmsvc_same_host: @@ -320,12 +321,15 @@ nlm_release_file(struct nlm_file *file) * returns 1 iff the host is a client. * Used by nlmsvc_invalidate_all */ + static int -nlmsvc_mark_host(void *data, struct nlm_host *dummy) +nlmsvc_mark_host(void *data, struct nlm_host *hint) { struct nlm_host *host = data; - host->h_inuse = 1; + if ((hint->net == NULL) || + (host->net == hint->net)) + host->h_inuse = 1; return 0; } @@ -358,10 +362,13 @@ nlmsvc_is_client(void *data, struct nlm_host *dummy) * Mark all hosts that still hold resources */ void -nlmsvc_mark_resources(void) +nlmsvc_mark_resources(struct net *net) { - dprintk("lockd: nlmsvc_mark_resources\n"); - nlm_traverse_files(NULL, nlmsvc_mark_host, NULL); + struct nlm_host hint; + + dprintk("lockd: nlmsvc_mark_resources for net %p\n", net); + hint.net = net; + nlm_traverse_files(&hint, nlmsvc_mark_host, NULL); } /* diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index f04ce6ac6d04..50e31a2c1a97 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -279,7 +279,7 @@ void nlmsvc_release_call(struct nlm_rqst *); __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, struct nfs_fh *); void nlm_release_file(struct nlm_file *); -void nlmsvc_mark_resources(void); +void nlmsvc_mark_resources(struct net *); void nlmsvc_free_host_resources(struct nlm_host *); void nlmsvc_invalidate_all(void); -- cgit v1.2.3 From 27adaddc8de7f523a172246d5104cf1cd5e2191b Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:03 +0400 Subject: LockD: make garbage collector network namespace aware. Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 2c5f41b098e9..991274a55664 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -45,7 +45,7 @@ static unsigned long next_gc; static unsigned long nrhosts; static DEFINE_MUTEX(nlm_host_mutex); -static void nlm_gc_hosts(void); +static void nlm_gc_hosts(struct net *net); struct nlm_lookup_host_info { const int server; /* search for server|client */ @@ -345,7 +345,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, mutex_lock(&nlm_host_mutex); if (time_after_eq(jiffies, next_gc)) - nlm_gc_hosts(); + nlm_gc_hosts(net); chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; hlist_for_each_entry(host, pos, chain, h_hash) { @@ -588,7 +588,7 @@ nlm_shutdown_hosts_net(struct net *net) } /* Then, perform a garbage collection pass */ - nlm_gc_hosts(); + nlm_gc_hosts(net); mutex_unlock(&nlm_host_mutex); } @@ -623,27 +623,31 @@ nlm_shutdown_hosts(void) * mark & sweep for resources held by remote clients. */ static void -nlm_gc_hosts(void) +nlm_gc_hosts(struct net *net) { struct hlist_head *chain; struct hlist_node *pos, *next; struct nlm_host *host; - struct net *net = &init_net; - dprintk("lockd: host garbage collection\n"); - for_each_host(host, pos, chain, nlm_server_hosts) + dprintk("lockd: host garbage collection for net %p\n", net); + for_each_host(host, pos, chain, nlm_server_hosts) { + if (net && host->net != net) + continue; host->h_inuse = 0; + } /* Mark all hosts that hold locks, blocks or shares */ nlmsvc_mark_resources(net); for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { + if (net && host->net != net) + continue; if (atomic_read(&host->h_count) || host->h_inuse || time_before(jiffies, host->h_expires)) { dprintk("nlm_gc_hosts skipping %s " - "(cnt %d use %d exp %ld)\n", + "(cnt %d use %d exp %ld net %p)\n", host->h_name, atomic_read(&host->h_count), - host->h_inuse, host->h_expires); + host->h_inuse, host->h_expires, host->net); continue; } nlm_destroy_host_locked(host); -- cgit v1.2.3 From 3cf7fb07e077e599d8343113cf4ef81adb2ca627 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:11 +0400 Subject: LockD: manage garbage collection timeout per networks namespace This patch moves next_gc to per-net data. Note: passed network can be NULL (when Lockd kthread is exiting of Lockd module is removing). Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 12 +++++++++--- fs/lockd/netns.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 991274a55664..3636734fe2ba 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -21,6 +21,8 @@ #include +#include "netns.h" + #define NLMDBG_FACILITY NLMDBG_HOSTCACHE #define NLM_HOST_NRHASH 32 #define NLM_HOST_REBIND (60 * HZ) @@ -41,7 +43,6 @@ static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; hlist_for_each_entry_safe((host), (pos), (next), \ (chain), h_hash) -static unsigned long next_gc; static unsigned long nrhosts; static DEFINE_MUTEX(nlm_host_mutex); @@ -337,6 +338,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, .hostname_len = hostname_len, .net = net, }; + struct lockd_net *ln = net_generic(net, lockd_net_id); dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, (int)hostname_len, hostname, rqstp->rq_vers, @@ -344,7 +346,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, mutex_lock(&nlm_host_mutex); - if (time_after_eq(jiffies, next_gc)) + if (time_after_eq(jiffies, ln->next_gc)) nlm_gc_hosts(net); chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; @@ -653,5 +655,9 @@ nlm_gc_hosts(struct net *net) nlm_destroy_host_locked(host); } - next_gc = jiffies + NLM_HOST_COLLECT; + if (net) { + struct lockd_net *ln = net_generic(net, lockd_net_id); + + ln->next_gc = jiffies + NLM_HOST_COLLECT; + } } diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index ce227e0fbc5c..97c6c771133f 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -5,6 +5,7 @@ struct lockd_net { unsigned int nlmsvc_users; + unsigned long next_gc; }; extern int lockd_net_id; -- cgit v1.2.3 From caa4e76b6f284bab535a98fd37b9c46856158bcb Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:19 +0400 Subject: LockD: manage used host count per networks namespace This patch introduces moves nrhosts in per-net data. It also adds kernel warning to nlm_shutdown_hosts_net() about remaining hosts in specified network namespace context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 18 ++++++++++++++++++ fs/lockd/netns.h | 1 + 2 files changed, 19 insertions(+) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3636734fe2ba..6c56090ca531 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -173,6 +173,7 @@ out: static void nlm_destroy_host_locked(struct nlm_host *host) { struct rpc_clnt *clnt; + struct lockd_net *ln = net_generic(host->net, lockd_net_id); dprintk("lockd: destroy host %s\n", host->h_name); @@ -189,6 +190,7 @@ static void nlm_destroy_host_locked(struct nlm_host *host) rpc_shutdown_client(clnt); kfree(host); + ln->nrhosts--; nrhosts--; } @@ -229,6 +231,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, struct hlist_node *pos; struct nlm_host *host; struct nsm_handle *nsm = NULL; + struct lockd_net *ln = net_generic(net, lockd_net_id); dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, (hostname ? hostname : ""), version, @@ -263,6 +266,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, goto out; hlist_add_head(&host->h_hash, chain); + ln->nrhosts++; nrhosts++; dprintk("lockd: %s created host %s (%s)\n", __func__, @@ -384,6 +388,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, memcpy(nlm_srcaddr(host), src_sap, src_len); host->h_srcaddrlen = src_len; hlist_add_head(&host->h_hash, chain); + ln->nrhosts++; nrhosts++; dprintk("lockd: %s created host %s (%s)\n", @@ -592,6 +597,19 @@ nlm_shutdown_hosts_net(struct net *net) /* Then, perform a garbage collection pass */ nlm_gc_hosts(net); mutex_unlock(&nlm_host_mutex); + + /* complain if any hosts are left */ + if (net) { + struct lockd_net *ln = net_generic(net, lockd_net_id); + + printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net); + dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net); + for_each_host(host, pos, chain, nlm_server_hosts) { + dprintk(" %s (cnt %d use %d exp %ld net %p)\n", + host->h_name, atomic_read(&host->h_count), + host->h_inuse, host->h_expires, host->net); + } + } } /* diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 97c6c771133f..44c8f0b9230a 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -6,6 +6,7 @@ struct lockd_net { unsigned int nlmsvc_users; unsigned long next_gc; + unsigned long nrhosts; }; extern int lockd_net_id; -- cgit v1.2.3 From d5850ff9eaaa9bed0f0b56702db105e02ce4b709 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:27 +0400 Subject: Lockd: host complaining function introduced Just a small cleanup. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 57 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 6c56090ca531..8cbf53d2c1bb 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -572,6 +572,35 @@ void nlm_host_rebooted(const struct nlm_reboot *info) nsm_release(nsm); } +static void nlm_complain_hosts(struct net *net) +{ + struct hlist_head *chain; + struct hlist_node *pos; + struct nlm_host *host; + + if (net) { + struct lockd_net *ln = net_generic(net, lockd_net_id); + + if (ln->nrhosts == 0) + return; + printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net); + dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net); + } else { + if (nrhosts == 0) + return; + printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); + dprintk("lockd: %lu hosts left:\n", nrhosts); + } + + for_each_host(host, pos, chain, nlm_server_hosts) { + if (net && host->net != net) + continue; + dprintk(" %s (cnt %d use %d exp %ld net %p)\n", + host->h_name, atomic_read(&host->h_count), + host->h_inuse, host->h_expires, host->net); + } +} + void nlm_shutdown_hosts_net(struct net *net) { @@ -598,18 +627,7 @@ nlm_shutdown_hosts_net(struct net *net) nlm_gc_hosts(net); mutex_unlock(&nlm_host_mutex); - /* complain if any hosts are left */ - if (net) { - struct lockd_net *ln = net_generic(net, lockd_net_id); - - printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net); - dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net); - for_each_host(host, pos, chain, nlm_server_hosts) { - dprintk(" %s (cnt %d use %d exp %ld net %p)\n", - host->h_name, atomic_read(&host->h_count), - host->h_inuse, host->h_expires, host->net); - } - } + nlm_complain_hosts(net); } /* @@ -619,22 +637,7 @@ nlm_shutdown_hosts_net(struct net *net) void nlm_shutdown_hosts(void) { - struct hlist_head *chain; - struct hlist_node *pos; - struct nlm_host *host; - nlm_shutdown_hosts_net(NULL); - - /* complain if any hosts are left */ - if (nrhosts != 0) { - printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); - dprintk("lockd: %lu hosts left:\n", nrhosts); - for_each_host(host, pos, chain, nlm_server_hosts) { - dprintk(" %s (cnt %d use %d exp %ld net %p)\n", - host->h_name, atomic_read(&host->h_count), - host->h_inuse, host->h_expires, host->net); - } - } } /* -- cgit v1.2.3 From e2edaa98cb2527c0f1c2d825ddb45a8b2d026669 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:35 +0400 Subject: Lockd: add more debug to host shutdown functions Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 8cbf53d2c1bb..0084ab853a2b 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -608,11 +608,10 @@ nlm_shutdown_hosts_net(struct net *net) struct hlist_node *pos; struct nlm_host *host; - dprintk("lockd: shutting down host module\n"); mutex_lock(&nlm_host_mutex); /* First, make all hosts eligible for gc */ - dprintk("lockd: nuking all hosts...\n"); + dprintk("lockd: nuking all hosts in net %p...\n", net); for_each_host(host, pos, chain, nlm_server_hosts) { if (net && host->net != net) continue; @@ -637,6 +636,7 @@ nlm_shutdown_hosts_net(struct net *net) void nlm_shutdown_hosts(void) { + dprintk("lockd: shutting down host module\n"); nlm_shutdown_hosts_net(NULL); } -- cgit v1.2.3 From 66547b0251b0b62dcb637631f566410a0e1e47a8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:43 +0400 Subject: LockD: manage grace period per network namespace Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/netns.h | 2 ++ fs/lockd/svc.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 44c8f0b9230a..94653aecfffb 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -7,6 +7,8 @@ struct lockd_net { unsigned int nlmsvc_users; unsigned long next_gc; unsigned long nrhosts; + + struct delayed_work grace_period_end; }; extern int lockd_net_id; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 80938fda67e0..70c417758eb9 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -95,21 +95,22 @@ static void grace_ender(struct work_struct *not_used) locks_end_grace(&lockd_manager); } -static DECLARE_DELAYED_WORK(grace_period_end, grace_ender); - static void set_grace_period(void) { unsigned long grace_period = get_lockd_grace_period(); + struct lockd_net *ln = net_generic(&init_net, lockd_net_id); locks_start_grace(&lockd_manager); - cancel_delayed_work_sync(&grace_period_end); - schedule_delayed_work(&grace_period_end, grace_period); + cancel_delayed_work_sync(&ln->grace_period_end); + schedule_delayed_work(&ln->grace_period_end, grace_period); } static void restart_grace(void) { if (nlmsvc_ops) { - cancel_delayed_work_sync(&grace_period_end); + struct lockd_net *ln = net_generic(&init_net, lockd_net_id); + + cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&lockd_manager); nlmsvc_invalidate_all(); set_grace_period(); @@ -124,6 +125,7 @@ lockd(void *vrqstp) { int err = 0, preverr = 0; struct svc_rqst *rqstp = vrqstp; + struct lockd_net *ln = net_generic(&init_net, lockd_net_id); /* try_to_freeze() is called from svc_recv() */ set_freezable(); @@ -184,7 +186,7 @@ lockd(void *vrqstp) svc_process(rqstp); } flush_signals(current); - cancel_delayed_work_sync(&grace_period_end); + cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&lockd_manager); if (nlmsvc_ops) nlmsvc_invalidate_all(); @@ -589,6 +591,9 @@ module_param(nlm_max_connections, uint, 0644); static int lockd_init_net(struct net *net) { + struct lockd_net *ln = net_generic(net, lockd_net_id); + + INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); return 0; } -- cgit v1.2.3 From 08d44a35a9e71a132c8e8abb0451b7b5e5b3dfee Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:50 +0400 Subject: LockD: make lockd manager allocated per network namespace Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/netns.h | 2 ++ fs/lockd/svc.c | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 94653aecfffb..e78650cb937c 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -1,6 +1,7 @@ #ifndef __LOCKD_NETNS_H__ #define __LOCKD_NETNS_H__ +#include #include struct lockd_net { @@ -9,6 +10,7 @@ struct lockd_net { unsigned long nrhosts; struct delayed_work grace_period_end; + struct lock_manager lockd_manager; }; extern int lockd_net_id; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 70c417758eb9..a9c436bc450c 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -87,12 +87,14 @@ static unsigned long get_lockd_grace_period(void) return nlm_timeout * 5 * HZ; } -static struct lock_manager lockd_manager = { -}; - -static void grace_ender(struct work_struct *not_used) +static void grace_ender(struct work_struct *grace) { - locks_end_grace(&lockd_manager); + struct delayed_work *dwork = container_of(grace, struct delayed_work, + work); + struct lockd_net *ln = container_of(dwork, struct lockd_net, + grace_period_end); + + locks_end_grace(&ln->lockd_manager); } static void set_grace_period(void) @@ -100,7 +102,7 @@ static void set_grace_period(void) unsigned long grace_period = get_lockd_grace_period(); struct lockd_net *ln = net_generic(&init_net, lockd_net_id); - locks_start_grace(&lockd_manager); + locks_start_grace(&ln->lockd_manager); cancel_delayed_work_sync(&ln->grace_period_end); schedule_delayed_work(&ln->grace_period_end, grace_period); } @@ -111,7 +113,7 @@ static void restart_grace(void) struct lockd_net *ln = net_generic(&init_net, lockd_net_id); cancel_delayed_work_sync(&ln->grace_period_end); - locks_end_grace(&lockd_manager); + locks_end_grace(&ln->lockd_manager); nlmsvc_invalidate_all(); set_grace_period(); } @@ -187,7 +189,7 @@ lockd(void *vrqstp) } flush_signals(current); cancel_delayed_work_sync(&ln->grace_period_end); - locks_end_grace(&lockd_manager); + locks_end_grace(&ln->lockd_manager); if (nlmsvc_ops) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); -- cgit v1.2.3 From 5e1533c7880bb0df98f71fa683979ec296aa947d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:56:58 +0400 Subject: NFSd: make nfsd4_manager allocated per network namespace context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/netns.h | 2 ++ fs/nfsd/nfs4state.c | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 39365636b244..e99767d987c8 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -34,6 +34,8 @@ struct nfsd_net { struct cache_detail *idtoname_cache; struct cache_detail *nametoid_cache; + + struct lock_manager nfsd4_manager; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fddb18b2e877..4a44b50c2f58 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -46,6 +46,8 @@ #include "current_stateid.h" #include "fault_inject.h" +#include "netns.h" + #define NFSDDBG_FACILITY NFSDDBG_PROC /* Globals */ @@ -3116,22 +3118,21 @@ out: return status; } -static struct lock_manager nfsd4_manager = { -}; - static bool grace_ended; static void -nfsd4_end_grace(void) +nfsd4_end_grace(struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + /* do nothing if grace period already ended */ if (grace_ended) return; dprintk("NFSD: end of grace period\n"); grace_ended = true; - nfsd4_record_grace_done(&init_net, boot_time); - locks_end_grace(&nfsd4_manager); + nfsd4_record_grace_done(net, boot_time); + locks_end_grace(&nn->nfsd4_manager); /* * Now that every NFSv4 client has had the chance to recover and * to see the (possibly new, possibly shorter) lease time, we @@ -3154,7 +3155,7 @@ nfs4_laundromat(void) nfs4_lock_state(); dprintk("NFSD: laundromat service - starting\n"); - nfsd4_end_grace(); + nfsd4_end_grace(&init_net); INIT_LIST_HEAD(&reaplist); spin_lock(&client_lock); list_for_each_safe(pos, next, &client_lru) { @@ -4688,6 +4689,8 @@ set_max_delegations(void) int nfs4_state_start(void) { + struct net *net = &init_net; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; /* @@ -4697,10 +4700,10 @@ nfs4_state_start(void) * to that instead and then do most of the rest of this on a per-net * basis. */ - get_net(&init_net); - nfsd4_client_tracking_init(&init_net); + get_net(net); + nfsd4_client_tracking_init(net); boot_time = get_seconds(); - locks_start_grace(&nfsd4_manager); + locks_start_grace(&nn->nfsd4_manager); grace_ended = false; printk(KERN_INFO "NFSD: starting %ld-second grace period\n", nfsd4_grace); @@ -4723,8 +4726,8 @@ nfs4_state_start(void) out_free_laundry: destroy_workqueue(laundry_wq); out_recovery: - nfsd4_client_tracking_exit(&init_net); - put_net(&init_net); + nfsd4_client_tracking_exit(net); + put_net(net); return ret; } @@ -4765,9 +4768,12 @@ __nfs4_state_shutdown(void) void nfs4_state_shutdown(void) { + struct net *net = &init_net; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + cancel_delayed_work_sync(&laundromat_work); destroy_workqueue(laundry_wq); - locks_end_grace(&nfsd4_manager); + locks_end_grace(&nn->nfsd4_manager); nfs4_lock_state(); __nfs4_state_shutdown(); nfs4_unlock_state(); -- cgit v1.2.3 From 9695c7057f4887ed54dc1e6c2ef22f72a2be1175 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:06 +0400 Subject: SUNRPC: service request network namespace helper introduced This is a cleanup patch - makes code looks simplier. It replaces widely used rqstp->rq_xprt->xpt_net by introduced SVC_NET(rqstp). Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 2 +- fs/nfs/callback_xdr.c | 4 ++-- fs/nfsd/export.c | 4 ++-- fs/nfsd/nfs4idmap.c | 4 ++-- include/linux/sunrpc/svc.h | 2 ++ 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 0084ab853a2b..f9b22e58f78f 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -331,7 +331,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, struct nsm_handle *nsm = NULL; struct sockaddr *src_sap = svc_daddr(rqstp); size_t src_len = rqstp->rq_daddrlen; - struct net *net = rqstp->rq_xprt->xpt_net; + struct net *net = SVC_NET(rqstp); struct nlm_lookup_host_info ni = { .server = 1, .sap = svc_addr(rqstp), diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index e64b01d2a338..742ff4ffced7 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -863,7 +863,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r .drc_status = 0, .clp = NULL, .slotid = NFS4_NO_SLOT, - .net = rqstp->rq_xprt->xpt_net, + .net = SVC_NET(rqstp), }; unsigned int nops = 0; @@ -879,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r return rpc_garbage_args; if (hdr_arg.minorversion == 0) { - cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident); + cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) return rpc_drop_reply; } diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 1114463bb856..a3946cf13fc8 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -929,7 +929,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) { struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); - struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct cache_detail *cd = nn->svc_export_cache; if (rqstp->rq_client == NULL) @@ -960,7 +960,7 @@ struct svc_export * rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) { struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); - struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct cache_detail *cd = nn->svc_export_cache; if (rqstp->rq_client == NULL) diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index dae36f1dee95..fdc91a6fc9c4 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -546,7 +546,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen .type = type, }; int ret; - struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (namelen + 1 > sizeof(key.name)) return nfserr_badowner; @@ -571,7 +571,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) .type = type, }; int ret; - struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 40e0a273faea..d83db800fe02 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -278,6 +278,8 @@ struct svc_rqst { struct task_struct *rq_task; /* service thread */ }; +#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net) + /* * Rigorous type checking on sockaddr type conversions */ -- cgit v1.2.3 From db9c4553412d72c6a05e0168d1d487f66e0660b3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:13 +0400 Subject: LockD: manage grace list per network namespace Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/grace.c | 14 +++++++++++--- fs/lockd/netns.h | 1 + fs/lockd/svc.c | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/lockd/grace.c b/fs/lockd/grace.c index 183cc1f0af1c..8dbaff782098 100644 --- a/fs/lockd/grace.c +++ b/fs/lockd/grace.c @@ -4,8 +4,10 @@ #include #include +#include + +#include "netns.h" -static LIST_HEAD(grace_list); static DEFINE_SPINLOCK(grace_lock); /** @@ -21,8 +23,11 @@ static DEFINE_SPINLOCK(grace_lock); */ void locks_start_grace(struct lock_manager *lm) { + struct net *net = &init_net; + struct lockd_net *ln = net_generic(net, lockd_net_id); + spin_lock(&grace_lock); - list_add(&lm->list, &grace_list); + list_add(&lm->list, &ln->grace_list); spin_unlock(&grace_lock); } EXPORT_SYMBOL_GPL(locks_start_grace); @@ -54,6 +59,9 @@ EXPORT_SYMBOL_GPL(locks_end_grace); */ int locks_in_grace(void) { - return !list_empty(&grace_list); + struct net *net = &init_net; + struct lockd_net *ln = net_generic(net, lockd_net_id); + + return !list_empty(&ln->grace_list); } EXPORT_SYMBOL_GPL(locks_in_grace); diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index e78650cb937c..4eee248ba96e 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -11,6 +11,7 @@ struct lockd_net { struct delayed_work grace_period_end; struct lock_manager lockd_manager; + struct list_head grace_list; }; extern int lockd_net_id; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index a9c436bc450c..834dfe2ed2e9 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -596,6 +596,7 @@ static int lockd_init_net(struct net *net) struct lockd_net *ln = net_generic(net, lockd_net_id); INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); + INIT_LIST_HEAD(&ln->grace_list); return 0; } -- cgit v1.2.3 From 5ccb0066f2d561549cc4d73d7f56b4ce3ca7a8a1 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:22 +0400 Subject: LockD: pass actual network namespace to grace period management functions Passed network namespace replaced hard-coded init_net Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/grace.c | 6 ++---- fs/lockd/svc.c | 16 +++++++++------- fs/lockd/svc4proc.c | 13 +++++++------ fs/lockd/svclock.c | 16 ++++++++-------- fs/lockd/svcproc.c | 15 +++++++++------ fs/nfsd/nfs4proc.c | 18 ++++++++++-------- fs/nfsd/nfs4state.c | 29 +++++++++++++++-------------- fs/nfsd/state.h | 3 ++- include/linux/fs.h | 5 +++-- include/linux/lockd/lockd.h | 4 ++-- 10 files changed, 67 insertions(+), 58 deletions(-) (limited to 'fs') diff --git a/fs/lockd/grace.c b/fs/lockd/grace.c index 8dbaff782098..6d1ee7204c88 100644 --- a/fs/lockd/grace.c +++ b/fs/lockd/grace.c @@ -21,9 +21,8 @@ static DEFINE_SPINLOCK(grace_lock); * * This function is called to start a grace period. */ -void locks_start_grace(struct lock_manager *lm) +void locks_start_grace(struct net *net, struct lock_manager *lm) { - struct net *net = &init_net; struct lockd_net *ln = net_generic(net, lockd_net_id); spin_lock(&grace_lock); @@ -57,9 +56,8 @@ EXPORT_SYMBOL_GPL(locks_end_grace); * to answer ordinary lock requests, and when they should accept only * lock reclaims. */ -int locks_in_grace(void) +int locks_in_grace(struct net *net) { - struct net *net = &init_net; struct lockd_net *ln = net_generic(net, lockd_net_id); return !list_empty(&ln->grace_list); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 834dfe2ed2e9..68271c206bdc 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -97,12 +97,12 @@ static void grace_ender(struct work_struct *grace) locks_end_grace(&ln->lockd_manager); } -static void set_grace_period(void) +static void set_grace_period(struct net *net) { unsigned long grace_period = get_lockd_grace_period(); - struct lockd_net *ln = net_generic(&init_net, lockd_net_id); + struct lockd_net *ln = net_generic(net, lockd_net_id); - locks_start_grace(&ln->lockd_manager); + locks_start_grace(net, &ln->lockd_manager); cancel_delayed_work_sync(&ln->grace_period_end); schedule_delayed_work(&ln->grace_period_end, grace_period); } @@ -110,12 +110,13 @@ static void set_grace_period(void) static void restart_grace(void) { if (nlmsvc_ops) { - struct lockd_net *ln = net_generic(&init_net, lockd_net_id); + struct net *net = &init_net; + struct lockd_net *ln = net_generic(net, lockd_net_id); cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&ln->lockd_manager); nlmsvc_invalidate_all(); - set_grace_period(); + set_grace_period(net); } } @@ -127,7 +128,8 @@ lockd(void *vrqstp) { int err = 0, preverr = 0; struct svc_rqst *rqstp = vrqstp; - struct lockd_net *ln = net_generic(&init_net, lockd_net_id); + struct net *net = &init_net; + struct lockd_net *ln = net_generic(net, lockd_net_id); /* try_to_freeze() is called from svc_recv() */ set_freezable(); @@ -141,7 +143,7 @@ lockd(void *vrqstp) nlm_timeout = LOCKD_DFLT_TIMEO; nlmsvc_timeout = nlm_timeout * HZ; - set_grace_period(); + set_grace_period(net); /* * The main request loop. We don't terminate until the last diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 9a41fdc19511..4a43d253c045 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -11,6 +11,7 @@ #include #include #include +#include #define NLMDBG_FACILITY NLMDBG_CLIENT @@ -151,7 +152,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(SVC_NET(rqstp))) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -161,7 +162,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ - resp->status = nlmsvc_cancel_blocked(file, &argp->lock); + resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock); dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); nlmsvc_release_host(host); @@ -184,7 +185,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept new lock requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(SVC_NET(rqstp))) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -194,7 +195,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ - resp->status = nlmsvc_unlock(file, &argp->lock); + resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock); dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); nlmsvc_release_host(host); @@ -321,7 +322,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept new lock requests during grace period */ - if (locks_in_grace() && !argp->reclaim) { + if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -354,7 +355,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(SVC_NET(rqstp))) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index e46353f41a42..afe4488c33d8 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -447,11 +447,11 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } - if (locks_in_grace() && !reclaim) { + if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) { ret = nlm_lck_denied_grace_period; goto out; } - if (reclaim && !locks_in_grace()) { + if (reclaim && !locks_in_grace(SVC_NET(rqstp))) { ret = nlm_lck_denied_grace_period; goto out; } @@ -559,7 +559,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } - if (locks_in_grace()) { + if (locks_in_grace(SVC_NET(rqstp))) { ret = nlm_lck_denied_grace_period; goto out; } @@ -603,7 +603,7 @@ out: * must be removed. */ __be32 -nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) +nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) { int error; @@ -615,7 +615,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) (long long)lock->fl.fl_end); /* First, cancel any lock that might be there */ - nlmsvc_cancel_blocked(file, lock); + nlmsvc_cancel_blocked(net, file, lock); lock->fl.fl_type = F_UNLCK; error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); @@ -631,7 +631,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) * The calling procedure must check whether the file can be closed. */ __be32 -nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) +nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock) { struct nlm_block *block; int status = 0; @@ -643,7 +643,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); - if (locks_in_grace()) + if (locks_in_grace(net)) return nlm_lck_denied_grace_period; mutex_lock(&file->f_mutex); diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d27aab11f324..de8f2caa2235 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -11,6 +11,7 @@ #include #include #include +#include #define NLMDBG_FACILITY NLMDBG_CLIENT @@ -175,13 +176,14 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, { struct nlm_host *host; struct nlm_file *file; + struct net *net = SVC_NET(rqstp); dprintk("lockd: CANCEL called\n"); resp->cookie = argp->cookie; /* Don't accept requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(net)) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -191,7 +193,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ - resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); + resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock)); dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); nlmsvc_release_host(host); @@ -208,13 +210,14 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, { struct nlm_host *host; struct nlm_file *file; + struct net *net = SVC_NET(rqstp); dprintk("lockd: UNLOCK called\n"); resp->cookie = argp->cookie; /* Don't accept new lock requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(net)) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -224,7 +227,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ - resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); + resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock)); dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); nlmsvc_release_host(host); @@ -361,7 +364,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept new lock requests during grace period */ - if (locks_in_grace() && !argp->reclaim) { + if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } @@ -394,7 +397,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; /* Don't accept requests during grace period */ - if (locks_in_grace()) { + if (locks_in_grace(SVC_NET(rqstp))) { resp->status = nlm_lck_denied_grace_period; return rpc_success; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 987e719fbae8..c9c1c0a25417 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -354,10 +354,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* Openowner is now set, so sequence id will get bumped. Now we need * these checks before we do any creates: */ status = nfserr_grace; - if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) + if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) goto out; status = nfserr_no_grace; - if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) + if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) goto out; switch (open->op_claim_type) { @@ -686,7 +686,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); /* check stateid */ - if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid, + if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), + cstate, &read->rd_stateid, RD_STATE, &read->rd_filp))) { dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; @@ -741,7 +742,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { __be32 status; - if (locks_in_grace()) + if (locks_in_grace(SVC_NET(rqstp))) return nfserr_grace; status = nfsd_unlink(rqstp, &cstate->current_fh, 0, remove->rm_name, remove->rm_namelen); @@ -760,8 +761,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!cstate->save_fh.fh_dentry) return status; - if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags - & NFSEXP_NOSUBTREECHECK)) + if (locks_in_grace(SVC_NET(rqstp)) && + !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) return nfserr_grace; status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, rename->rn_snamelen, &cstate->current_fh, @@ -845,7 +846,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(cstate, + status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, &setattr->sa_stateid, WR_STATE, NULL); nfs4_unlock_state(); if (status) { @@ -890,7 +891,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfserr_inval; nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp); + status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), + cstate, stateid, WR_STATE, &filp); if (filp) get_file(filp); nfs4_unlock_state(); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4a44b50c2f58..34f65f10fa43 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2885,7 +2885,8 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) * Attempt to hand out a delegation. */ static void -nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp) +nfs4_open_delegation(struct net *net, struct svc_fh *fh, + struct nfsd4_open *open, struct nfs4_ol_stateid *stp) { struct nfs4_delegation *dp; struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); @@ -2906,7 +2907,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_ case NFS4_OPEN_CLAIM_NULL: /* Let's not give out any delegations till everyone's * had the chance to reclaim theirs.... */ - if (locks_in_grace()) + if (locks_in_grace(net)) goto out; if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) goto out; @@ -3040,7 +3041,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf * Attempt to hand out a delegation. No error return, because the * OPEN succeeds even if we fail. */ - nfs4_open_delegation(current_fh, open, stp); + nfs4_open_delegation(SVC_NET(rqstp), current_fh, open, stp); nodeleg: status = nfs_ok; @@ -3279,11 +3280,11 @@ out: } static inline __be32 -check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) +check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) { if (ONE_STATEID(stateid) && (flags & RD_STATE)) return nfs_ok; - else if (locks_in_grace()) { + else if (locks_in_grace(net)) { /* Answer in remaining cases depends on existence of * conflicting state; so we must wait out the grace period. */ return nfserr_grace; @@ -3300,9 +3301,9 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) * that are not able to provide mandatory locking. */ static inline int -grace_disallows_io(struct inode *inode) +grace_disallows_io(struct net *net, struct inode *inode) { - return locks_in_grace() && mandatory_lock(inode); + return locks_in_grace(net) && mandatory_lock(inode); } /* Returns true iff a is later than b: */ @@ -3393,7 +3394,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s * Checks for stateid operations */ __be32 -nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, +nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, stateid_t *stateid, int flags, struct file **filpp) { struct nfs4_stid *s; @@ -3406,11 +3407,11 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, if (filpp) *filpp = NULL; - if (grace_disallows_io(ino)) + if (grace_disallows_io(net, ino)) return nfserr_grace; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) - return check_special_stateids(current_fh, stateid, flags); + return check_special_stateids(net, current_fh, stateid, flags); status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); if (status) @@ -4107,10 +4108,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; status = nfserr_grace; - if (locks_in_grace() && !lock->lk_reclaim) + if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim) goto out; status = nfserr_no_grace; - if (!locks_in_grace() && lock->lk_reclaim) + if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) goto out; locks_init_lock(&file_lock); @@ -4210,7 +4211,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_lockowner *lo; __be32 status; - if (locks_in_grace()) + if (locks_in_grace(SVC_NET(rqstp))) return nfserr_grace; if (check_lock_length(lockt->lt_offset, lockt->lt_length)) @@ -4703,7 +4704,7 @@ nfs4_state_start(void) get_net(net); nfsd4_client_tracking_init(net); boot_time = get_seconds(); - locks_start_grace(&nn->nfsd4_manager); + locks_start_grace(net, &nn->nfsd4_manager); grace_ended = false; printk(KERN_INFO "NFSD: starting %ld-second grace period\n", nfsd4_grace); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 495df4e3aa67..981ef10141b3 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -451,7 +451,8 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) struct nfsd4_compound_state; -extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, +extern __be32 nfs4_preprocess_stateid_op(struct net *net, + struct nfsd4_compound_state *cstate, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); diff --git a/include/linux/fs.h b/include/linux/fs.h index 17fd887c798f..a1e77270f5a5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1163,9 +1163,10 @@ struct lock_manager { struct list_head list; }; -void locks_start_grace(struct lock_manager *); +struct net; +void locks_start_grace(struct net *, struct lock_manager *); void locks_end_grace(struct lock_manager *); -int locks_in_grace(void); +int locks_in_grace(struct net *); /* that will die - we need it for nfs_lock_info */ #include diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 50e31a2c1a97..f5a051a79273 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -262,11 +262,11 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, struct nlm_host *, struct nlm_lock *, int, struct nlm_cookie *, int); -__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *); __be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *, struct nlm_host *, struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *); -__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); -- cgit v1.2.3 From 5630f7fa97e8dfa2b3c6e7370c1702180336e493 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:29 +0400 Subject: Lockd: move grace period management from lockd() to per-net functions Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/lockd/svc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 68271c206bdc..31a63f87b806 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -128,8 +128,6 @@ lockd(void *vrqstp) { int err = 0, preverr = 0; struct svc_rqst *rqstp = vrqstp; - struct net *net = &init_net; - struct lockd_net *ln = net_generic(net, lockd_net_id); /* try_to_freeze() is called from svc_recv() */ set_freezable(); @@ -143,8 +141,6 @@ lockd(void *vrqstp) nlm_timeout = LOCKD_DFLT_TIMEO; nlmsvc_timeout = nlm_timeout * HZ; - set_grace_period(net); - /* * The main request loop. We don't terminate until the last * NFS mount or NFS daemon has gone away. @@ -190,8 +186,6 @@ lockd(void *vrqstp) svc_process(rqstp); } flush_signals(current); - cancel_delayed_work_sync(&ln->grace_period_end); - locks_end_grace(&ln->lockd_manager); if (nlmsvc_ops) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); @@ -272,6 +266,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net) error = make_socks(serv, net); if (error < 0) goto err_socks; + set_grace_period(net); dprintk("lockd_up_net: per-net data created; net=%p\n", net); return 0; @@ -289,6 +284,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) if (ln->nlmsvc_users) { if (--ln->nlmsvc_users == 0) { nlm_shutdown_hosts_net(net); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); svc_shutdown_net(serv, net); dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); } -- cgit v1.2.3 From a51c84ed502c25fed996afb7696fd7db2fa32fe2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:37 +0400 Subject: NFSd: make grace end flag per network namespace Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/netns.h | 1 + fs/nfsd/nfs4state.c | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index e99767d987c8..b6deebd08ef2 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -36,6 +36,7 @@ struct nfsd_net { struct cache_detail *nametoid_cache; struct lock_manager nfsd4_manager; + bool grace_ended; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 34f65f10fa43..aebb58d3ac4a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3119,19 +3119,17 @@ out: return status; } -static bool grace_ended; - static void nfsd4_end_grace(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); /* do nothing if grace period already ended */ - if (grace_ended) + if (nn->grace_ended) return; dprintk("NFSD: end of grace period\n"); - grace_ended = true; + nn->grace_ended = true; nfsd4_record_grace_done(net, boot_time); locks_end_grace(&nn->nfsd4_manager); /* @@ -4705,7 +4703,7 @@ nfs4_state_start(void) nfsd4_client_tracking_init(net); boot_time = get_seconds(); locks_start_grace(net, &nn->nfsd4_manager); - grace_ended = false; + nn->grace_ended = false; printk(KERN_INFO "NFSD: starting %ld-second grace period\n", nfsd4_grace); ret = set_callback_cred(); -- cgit v1.2.3 From 2c142baa7b237584bae7dc28630851701497e1ef Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Jul 2012 16:57:45 +0400 Subject: NFSd: make boot_time variable per network namespace NFSd's boot_time represents grace period start point in time. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- fs/nfsd/netns.h | 1 + fs/nfsd/nfs4state.c | 39 +++++++++++++++++++++++---------------- fs/nfsd/state.h | 1 + 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index b6deebd08ef2..65c2431ea32f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -37,6 +37,7 @@ struct nfsd_net { struct lock_manager nfsd4_manager; bool grace_ended; + time_t boot_time; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index aebb58d3ac4a..cc894eda385a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -53,7 +53,6 @@ /* Globals */ time_t nfsd4_lease = 90; /* default lease time */ time_t nfsd4_grace = 90; -static time_t boot_time; #define all_ones {{~0,~0},~0} static const stateid_t one_stateid = { @@ -1056,12 +1055,12 @@ renew_client(struct nfs4_client *clp) /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ static int -STALE_CLIENTID(clientid_t *clid) +STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) { - if (clid->cl_boot == boot_time) + if (clid->cl_boot == nn->boot_time) return 0; dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", - clid->cl_boot, clid->cl_id, boot_time); + clid->cl_boot, clid->cl_id, nn->boot_time); return 1; } @@ -1242,8 +1241,9 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) static void gen_clid(struct nfs4_client *clp) { static u32 current_clientid = 1; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - clp->cl_clientid.cl_boot = boot_time; + clp->cl_clientid.cl_boot = nn->boot_time; clp->cl_clientid.cl_id = current_clientid++; } @@ -2226,8 +2226,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; __be32 status; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - if (STALE_CLIENTID(clid)) + if (STALE_CLIENTID(clid, nn)) return nfserr_stale_clientid; nfs4_lock_state(); @@ -2586,8 +2587,9 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, unsigned int strhashval; struct nfs4_openowner *oo = NULL; __be32 status; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - if (STALE_CLIENTID(&open->op_clientid)) + if (STALE_CLIENTID(&open->op_clientid, nn)) return nfserr_stale_clientid; /* * In case we need it later, after we've already created the @@ -3095,12 +3097,13 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfs4_client *clp; __be32 status; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", clid->cl_boot, clid->cl_id); status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid)) + if (STALE_CLIENTID(clid, nn)) goto out; clp = find_confirmed_client(clid); status = nfserr_expired; @@ -3130,7 +3133,7 @@ nfsd4_end_grace(struct net *net) dprintk("NFSD: end of grace period\n"); nn->grace_ended = true; - nfsd4_record_grace_done(net, boot_time); + nfsd4_record_grace_done(net, nn->boot_time); locks_end_grace(&nn->nfsd4_manager); /* * Now that every NFSv4 client has had the chance to recover and @@ -3236,9 +3239,9 @@ static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *s } static int -STALE_STATEID(stateid_t *stateid) +STALE_STATEID(stateid_t *stateid, struct nfsd_net *nn) { - if (stateid->si_opaque.so_clid.cl_boot == boot_time) + if (stateid->si_opaque.so_clid.cl_boot == nn->boot_time) return 0; dprintk("NFSD: stale stateid " STATEID_FMT "!\n", STATEID_VAL(stateid)); @@ -3373,10 +3376,11 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) { struct nfs4_client *cl; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return nfserr_bad_stateid; - if (STALE_STATEID(stateid)) + if (STALE_STATEID(stateid, nn)) return nfserr_stale_stateid; cl = find_confirmed_client(&stateid->si_opaque.so_clid); if (!cl) @@ -4048,6 +4052,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, bool new_state = false; int lkflg; int err; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", (long long) lock->lk_offset, @@ -4074,7 +4079,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, sizeof(clientid_t)); status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lock->lk_new_clientid)) + if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) goto out; /* validate and update open stateid and open seqid */ @@ -4208,6 +4213,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct file_lock file_lock; struct nfs4_lockowner *lo; __be32 status; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); if (locks_in_grace(SVC_NET(rqstp))) return nfserr_grace; @@ -4218,7 +4224,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); status = nfserr_stale_clientid; - if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) + if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn)) goto out; if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) @@ -4367,6 +4373,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct list_head matches; unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); __be32 status; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", clid->cl_boot, clid->cl_id); @@ -4374,7 +4381,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, /* XXX check for lease expiration */ status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid)) + if (STALE_CLIENTID(clid, nn)) return status; nfs4_lock_state(); @@ -4701,7 +4708,7 @@ nfs4_state_start(void) */ get_net(net); nfsd4_client_tracking_init(net); - boot_time = get_seconds(); + nn->boot_time = get_seconds(); locks_start_grace(net, &nn->nfsd4_manager); nn->grace_ended = false; printk(KERN_INFO "NFSD: starting %ld-second grace period\n", diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 981ef10141b3..e6173147f982 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -450,6 +450,7 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) #define WR_STATE 0x00000020 struct nfsd4_compound_state; +struct nfsd_net; extern __be32 nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, -- cgit v1.2.3