aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-11-12 15:00:55 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-11-12 18:55:11 -0500
commit0ce0c2b5d23080eec39ccc52354be1eea326ed5f (patch)
tree560db260bfd579a0b78f75eca46fbf67a90ed6ed /fs/nfsd
parent772a9bbbb5769c646c74452ef21df538bbe2ebf0 (diff)
nfsd: don't search for client by hash on legacy reboot recovery gracedone
When nfsd starts, the legacy reboot recovery code creates a tracking struct for each directory in the v4recoverydir. When the grace period ends, it basically does a "readdir" on the directory again, and matches each dentry in there to an existing client id to see if it should be removed or not. If the matching client doesn't exist, or hasn't reclaimed its state then it will remove that dentry. This is pretty inefficient since it involves doing a lot of hash-bucket searching. It also means that we have to keep relying on being able to search for a nfs4_client by md5 hashed cl_recdir name. Instead, add a pointer to the nfs4_client that indicates the association between the nfs4_client_reclaim and nfs4_client. When a reclaim operation comes in, we set the pointer to make that association. On gracedone, the legacy client tracker will keep the recdir around iff: 1/ there is a reclaim record for the directory ...and... 2/ there's an association between the reclaim record and a client record -- that is, a create or check operation was performed on the client that matches that directory. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4recover.c31
-rw-r--r--fs/nfsd/nfs4state.c12
-rw-r--r--fs/nfsd/state.h4
3 files changed, 34 insertions, 13 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 4e92fb38cfb2..3048c012d4bc 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -65,6 +65,7 @@ struct nfsd4_client_tracking_ops {
65static struct file *rec_file; 65static struct file *rec_file;
66static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; 66static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
67static struct nfsd4_client_tracking_ops *client_tracking_ops; 67static struct nfsd4_client_tracking_ops *client_tracking_ops;
68static bool in_grace;
68 69
69static int 70static int
70nfs4_save_creds(const struct cred **original_creds) 71nfs4_save_creds(const struct cred **original_creds)
@@ -142,6 +143,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
142 const struct cred *original_cred; 143 const struct cred *original_cred;
143 char *dname = clp->cl_recdir; 144 char *dname = clp->cl_recdir;
144 struct dentry *dir, *dentry; 145 struct dentry *dir, *dentry;
146 struct nfs4_client_reclaim *crp;
145 int status; 147 int status;
146 148
147 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); 149 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -182,13 +184,19 @@ out_put:
182 dput(dentry); 184 dput(dentry);
183out_unlock: 185out_unlock:
184 mutex_unlock(&dir->d_inode->i_mutex); 186 mutex_unlock(&dir->d_inode->i_mutex);
185 if (status == 0) 187 if (status == 0) {
188 if (in_grace) {
189 crp = nfs4_client_to_reclaim(clp->cl_recdir);
190 if (crp)
191 crp->cr_clp = clp;
192 }
186 vfs_fsync(rec_file, 0); 193 vfs_fsync(rec_file, 0);
187 else 194 } else {
188 printk(KERN_ERR "NFSD: failed to write recovery record" 195 printk(KERN_ERR "NFSD: failed to write recovery record"
189 " (err %d); please check that %s exists" 196 " (err %d); please check that %s exists"
190 " and is writeable", status, 197 " and is writeable", status,
191 user_recovery_dirname); 198 user_recovery_dirname);
199 }
192 mnt_drop_write_file(rec_file); 200 mnt_drop_write_file(rec_file);
193 nfs4_reset_creds(original_cred); 201 nfs4_reset_creds(original_cred);
194} 202}
@@ -289,6 +297,7 @@ static void
289nfsd4_remove_clid_dir(struct nfs4_client *clp) 297nfsd4_remove_clid_dir(struct nfs4_client *clp)
290{ 298{
291 const struct cred *original_cred; 299 const struct cred *original_cred;
300 struct nfs4_client_reclaim *crp;
292 int status; 301 int status;
293 302
294 if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 303 if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
@@ -305,8 +314,15 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
305 314
306 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 315 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
307 nfs4_reset_creds(original_cred); 316 nfs4_reset_creds(original_cred);
308 if (status == 0) 317 if (status == 0) {
309 vfs_fsync(rec_file, 0); 318 vfs_fsync(rec_file, 0);
319 if (in_grace) {
320 /* remove reclaim record */
321 crp = nfsd4_find_reclaim_client(clp->cl_recdir);
322 if (crp)
323 nfs4_remove_reclaim_record(crp);
324 }
325 }
310out_drop_write: 326out_drop_write:
311 mnt_drop_write_file(rec_file); 327 mnt_drop_write_file(rec_file);
312out: 328out:
@@ -336,6 +352,7 @@ nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
336{ 352{
337 int status; 353 int status;
338 354
355 in_grace = false;
339 if (!rec_file) 356 if (!rec_file)
340 return; 357 return;
341 status = mnt_want_write_file(rec_file); 358 status = mnt_want_write_file(rec_file);
@@ -410,6 +427,8 @@ nfsd4_init_recdir(void)
410 } 427 }
411 428
412 nfs4_reset_creds(original_cred); 429 nfs4_reset_creds(original_cred);
430 if (!status)
431 in_grace = true;
413 return status; 432 return status;
414} 433}
415 434
@@ -481,13 +500,17 @@ nfs4_recoverydir(void)
481static int 500static int
482nfsd4_check_legacy_client(struct nfs4_client *clp) 501nfsd4_check_legacy_client(struct nfs4_client *clp)
483{ 502{
503 struct nfs4_client_reclaim *crp;
504
484 /* did we already find that this client is stable? */ 505 /* did we already find that this client is stable? */
485 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 506 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
486 return 0; 507 return 0;
487 508
488 /* look for it in the reclaim hashtable otherwise */ 509 /* look for it in the reclaim hashtable otherwise */
489 if (nfsd4_find_reclaim_client(clp->cl_recdir)) { 510 crp = nfsd4_find_reclaim_client(clp->cl_recdir);
511 if (crp) {
490 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 512 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
513 crp->cr_clp = clp;
491 return 0; 514 return 0;
492 } 515 }
493 516
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1c6f82e4335e..559ab574d46b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4483,16 +4483,13 @@ alloc_reclaim(void)
4483 return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 4483 return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
4484} 4484}
4485 4485
4486int 4486bool
4487nfs4_has_reclaimed_state(const char *name) 4487nfs4_has_reclaimed_state(const char *name)
4488{ 4488{
4489 unsigned int strhashval = clientstr_hashval(name); 4489 struct nfs4_client_reclaim *crp;
4490 struct nfs4_client *clp;
4491 4490
4492 clp = find_confirmed_client_by_str(name, strhashval); 4491 crp = nfsd4_find_reclaim_client(name);
4493 if (!clp) 4492 return (crp && crp->cr_clp);
4494 return 0;
4495 return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
4496} 4493}
4497 4494
4498/* 4495/*
@@ -4511,6 +4508,7 @@ nfs4_client_to_reclaim(const char *name)
4511 INIT_LIST_HEAD(&crp->cr_strhash); 4508 INIT_LIST_HEAD(&crp->cr_strhash);
4512 list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); 4509 list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
4513 memcpy(crp->cr_recdir, name, HEXDIR_LEN); 4510 memcpy(crp->cr_recdir, name, HEXDIR_LEN);
4511 crp->cr_clp = NULL;
4514 reclaim_str_hashtbl_size++; 4512 reclaim_str_hashtbl_size++;
4515 } 4513 }
4516 return crp; 4514 return crp;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 3f8b26b9b47b..cf9f7ba4df8d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -304,6 +304,7 @@ is_client_expired(struct nfs4_client *clp)
304 */ 304 */
305struct nfs4_client_reclaim { 305struct nfs4_client_reclaim {
306 struct list_head cr_strhash; /* hash by cr_name */ 306 struct list_head cr_strhash; /* hash by cr_name */
307 struct nfs4_client *cr_clp; /* pointer to associated clp */
307 char cr_recdir[HEXDIR_LEN]; /* recover dir */ 308 char cr_recdir[HEXDIR_LEN]; /* recover dir */
308}; 309};
309 310
@@ -464,7 +465,6 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net,
464 stateid_t *stateid, int flags, struct file **filp); 465 stateid_t *stateid, int flags, struct file **filp);
465extern void nfs4_lock_state(void); 466extern void nfs4_lock_state(void);
466extern void nfs4_unlock_state(void); 467extern void nfs4_unlock_state(void);
467extern int nfs4_in_grace(void);
468void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *); 468void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *);
469extern void nfs4_release_reclaim(void); 469extern void nfs4_release_reclaim(void);
470extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir); 470extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir);
@@ -483,7 +483,7 @@ extern void nfsd4_shutdown_callback(struct nfs4_client *);
483extern void nfs4_put_delegation(struct nfs4_delegation *dp); 483extern void nfs4_put_delegation(struct nfs4_delegation *dp);
484extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); 484extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
485extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); 485extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name);
486extern int nfs4_has_reclaimed_state(const char *name); 486extern bool nfs4_has_reclaimed_state(const char *name);
487extern void release_session_client(struct nfsd4_session *); 487extern void release_session_client(struct nfsd4_session *);
488extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); 488extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
489 489