Skip to content

Commit 19d008b

Browse files
neilbrownchucklever
authored andcommitted
NFSD: reduce locking in nfsd_lookup()
nfsd_lookup() takes an exclusive lock on the parent inode, but no callers want the lock and it may not be needed at all if the result is in the dcache. Change nfsd_lookup_dentry() to not take the lock, and call lookup_one_len_locked() which takes lock only if needed. nfsd4_open() currently expects the lock to still be held, but that isn't necessary as nfsd_validate_delegated_dentry() provides required guarantees without the lock. NOTE: NFSv4 requires directory changeinfo for OPEN even when a create wasn't requested and no change happened. Now that nfsd_lookup() doesn't use fh_lock(), we need to explicitly fill the attributes when no create happens. A new fh_fill_both_attrs() is provided for that task. Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent e18bcb3 commit 19d008b

File tree

5 files changed

+46
-32
lines changed

5 files changed

+46
-32
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
302302
if (d_really_is_positive(child)) {
303303
status = nfs_ok;
304304

305+
/* NFSv4 protocol requires change attributes even though
306+
* no change happened.
307+
*/
308+
fh_fill_both_attrs(fhp);
309+
305310
switch (open->op_createmode) {
306311
case NFS4_CREATE_UNCHECKED:
307312
if (!d_is_reg(child))
@@ -417,15 +422,15 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
417422
if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
418423
open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
419424
FATTR4_WORD1_TIME_MODIFY);
420-
} else
421-
/*
422-
* Note this may exit with the parent still locked.
423-
* We will hold the lock until nfsd4_open's final
424-
* lookup, to prevent renames or unlinks until we've had
425-
* a chance to an acquire a delegation if appropriate.
426-
*/
425+
} else {
427426
status = nfsd_lookup(rqstp, current_fh,
428427
open->op_fname, open->op_fnamelen, *resfh);
428+
if (!status)
429+
/* NFSv4 protocol requires change attributes even though
430+
* no change happened.
431+
*/
432+
fh_fill_both_attrs(current_fh);
433+
}
429434
if (status)
430435
goto out;
431436
status = nfsd_check_obj_isreg(*resfh);
@@ -1043,7 +1048,6 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
10431048
&exp, &dentry);
10441049
if (err)
10451050
return err;
1046-
fh_unlock(&cstate->current_fh);
10471051
if (d_really_is_negative(dentry)) {
10481052
exp_put(exp);
10491053
err = nfserr_noent;

fs/nfsd/nfs4state.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5304,9 +5304,6 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
53045304
struct dentry *child;
53055305
__be32 err;
53065306

5307-
/* parent may already be locked, and it may get unlocked by
5308-
* this call, but that is safe.
5309-
*/
53105307
err = nfsd_lookup_dentry(open->op_rqstp, parent,
53115308
open->op_fname, open->op_fnamelen,
53125309
&exp, &child);

fs/nfsd/nfsfh.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,25 @@ void fh_fill_post_attrs(struct svc_fh *fhp)
672672
nfsd4_change_attribute(&fhp->fh_post_attr, inode);
673673
}
674674

675+
/**
676+
* fh_fill_both_attrs - Fill pre-op and post-op attributes
677+
* @fhp: file handle to be updated
678+
*
679+
* This is used when the directory wasn't changed, but wcc attributes
680+
* are needed anyway.
681+
*/
682+
void fh_fill_both_attrs(struct svc_fh *fhp)
683+
{
684+
fh_fill_post_attrs(fhp);
685+
if (!fhp->fh_post_saved)
686+
return;
687+
fhp->fh_pre_change = fhp->fh_post_change;
688+
fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
689+
fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
690+
fhp->fh_pre_size = fhp->fh_post_attr.size;
691+
fhp->fh_pre_saved = true;
692+
}
693+
675694
/*
676695
* Release a file handle.
677696
*/

fs/nfsd/nfsfh.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
322322

323323
extern void fh_fill_pre_attrs(struct svc_fh *fhp);
324324
extern void fh_fill_post_attrs(struct svc_fh *fhp);
325-
325+
extern void fh_fill_both_attrs(struct svc_fh *fhp);
326326

327327
/*
328328
* Lock a file handle/inode

fs/nfsd/vfs.c

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -199,27 +199,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
199199
goto out_nfserr;
200200
}
201201
} else {
202-
/*
203-
* In the nfsd4_open() case, this may be held across
204-
* subsequent open and delegation acquisition which may
205-
* need to take the child's i_mutex:
206-
*/
207-
fh_lock_nested(fhp, I_MUTEX_PARENT);
208-
dentry = lookup_one_len(name, dparent, len);
202+
dentry = lookup_one_len_unlocked(name, dparent, len);
209203
host_err = PTR_ERR(dentry);
210204
if (IS_ERR(dentry))
211205
goto out_nfserr;
212206
if (nfsd_mountpoint(dentry, exp)) {
213-
/*
214-
* We don't need the i_mutex after all. It's
215-
* still possible we could open this (regular
216-
* files can be mountpoints too), but the
217-
* i_mutex is just there to prevent renames of
218-
* something that we might be about to delegate,
219-
* and a mountpoint won't be renamed:
220-
*/
221-
fh_unlock(fhp);
222-
if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
207+
host_err = nfsd_cross_mnt(rqstp, &dentry, &exp);
208+
if (host_err) {
223209
dput(dentry);
224210
goto out_nfserr;
225211
}
@@ -234,7 +220,15 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
234220
return nfserrno(host_err);
235221
}
236222

237-
/*
223+
/**
224+
* nfsd_lookup - look up a single path component for nfsd
225+
*
226+
* @rqstp: the request context
227+
* @fhp: the file handle of the directory
228+
* @name: the component name, or %NULL to look up parent
229+
* @len: length of name to examine
230+
* @resfh: pointer to pre-initialised filehandle to hold result.
231+
*
238232
* Look up one component of a pathname.
239233
* N.B. After this call _both_ fhp and resfh need an fh_put
240234
*
@@ -244,11 +238,11 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
244238
* returned. Otherwise the covered directory is returned.
245239
* NOTE: this mountpoint crossing is not supported properly by all
246240
* clients and is explicitly disallowed for NFSv3
247-
* NeilBrown <[email protected]>
241+
*
248242
*/
249243
__be32
250244
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
251-
unsigned int len, struct svc_fh *resfh)
245+
unsigned int len, struct svc_fh *resfh)
252246
{
253247
struct svc_export *exp;
254248
struct dentry *dentry;

0 commit comments

Comments
 (0)