Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'nfsd-6.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd fixes from Chuck Lever:
"A set of NFSD fixes that arrived just a bit late for the 6.19 merge
window.

Regression fix:
- Avoid unnecessarily breaking a timestamp delegation

Stable fixes:
- Fix a crasher in nlm4svc_proc_test()
- Fix nfsd_file reference leak during write delegation
- Fix error flow in client_states_open()"

* tag 'nfsd-6.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
nfsd: Drop the client reference in client_states_open()
nfsd: use ATTR_DELEG in nfsd4_finalize_deleg_timestamps()
nfsd: fix nfsd_file reference leak in nfsd4_add_rdaccess_to_wrdeleg()
lockd: fix vfs_test_lock() calls

+38 -24
+1 -3
fs/lockd/svc4proc.c
··· 97 97 struct nlm_args *argp = rqstp->rq_argp; 98 98 struct nlm_host *host; 99 99 struct nlm_file *file; 100 - struct nlm_lockowner *test_owner; 101 100 __be32 rc = rpc_success; 102 101 103 102 dprintk("lockd: TEST4 called\n"); ··· 106 107 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 107 108 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 108 109 109 - test_owner = argp->lock.fl.c.flc_owner; 110 110 /* Now check for conflicting locks */ 111 111 resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, 112 112 &resp->lock); ··· 114 116 else 115 117 dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); 116 118 117 - nlmsvc_put_lockowner(test_owner); 119 + nlmsvc_release_lockowner(&argp->lock); 118 120 nlmsvc_release_host(host); 119 121 nlm_release_file(file); 120 122 return rc;
+12 -9
fs/lockd/svclock.c
··· 633 633 } 634 634 635 635 mode = lock_to_openmode(&lock->fl); 636 - error = vfs_test_lock(file->f_file[mode], &lock->fl); 636 + locks_init_lock(&conflock->fl); 637 + /* vfs_test_lock only uses start, end, and owner, but tests flc_file */ 638 + conflock->fl.c.flc_file = lock->fl.c.flc_file; 639 + conflock->fl.fl_start = lock->fl.fl_start; 640 + conflock->fl.fl_end = lock->fl.fl_end; 641 + conflock->fl.c.flc_owner = lock->fl.c.flc_owner; 642 + error = vfs_test_lock(file->f_file[mode], &conflock->fl); 637 643 if (error) { 638 644 /* We can't currently deal with deferred test requests */ 639 645 if (error == FILE_LOCK_DEFERRED) ··· 649 643 goto out; 650 644 } 651 645 652 - if (lock->fl.c.flc_type == F_UNLCK) { 646 + if (conflock->fl.c.flc_type == F_UNLCK) { 653 647 ret = nlm_granted; 654 648 goto out; 655 649 } 656 650 657 651 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", 658 - lock->fl.c.flc_type, (long long)lock->fl.fl_start, 659 - (long long)lock->fl.fl_end); 652 + conflock->fl.c.flc_type, (long long)conflock->fl.fl_start, 653 + (long long)conflock->fl.fl_end); 660 654 conflock->caller = "somehost"; /* FIXME */ 661 655 conflock->len = strlen(conflock->caller); 662 656 conflock->oh.len = 0; /* don't return OH info */ 663 - conflock->svid = lock->fl.c.flc_pid; 664 - conflock->fl.c.flc_type = lock->fl.c.flc_type; 665 - conflock->fl.fl_start = lock->fl.fl_start; 666 - conflock->fl.fl_end = lock->fl.fl_end; 667 - locks_release_private(&lock->fl); 657 + conflock->svid = conflock->fl.c.flc_pid; 658 + locks_release_private(&conflock->fl); 668 659 669 660 ret = nlm_lck_denied; 670 661 out:
+1 -4
fs/lockd/svcproc.c
··· 117 117 struct nlm_args *argp = rqstp->rq_argp; 118 118 struct nlm_host *host; 119 119 struct nlm_file *file; 120 - struct nlm_lockowner *test_owner; 121 120 __be32 rc = rpc_success; 122 121 123 122 dprintk("lockd: TEST called\n"); ··· 125 126 /* Obtain client and file */ 126 127 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 127 128 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 128 - 129 - test_owner = argp->lock.fl.c.flc_owner; 130 129 131 130 /* Now check for conflicting locks */ 132 131 resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, ··· 135 138 dprintk("lockd: TEST status %d vers %d\n", 136 139 ntohl(resp->status), rqstp->rq_vers); 137 140 138 - nlmsvc_put_lockowner(test_owner); 141 + nlmsvc_release_lockowner(&argp->lock); 139 142 nlmsvc_release_host(host); 140 143 nlm_release_file(file); 141 144 return rc;
+10 -2
fs/locks.c
··· 2236 2236 /** 2237 2237 * vfs_test_lock - test file byte range lock 2238 2238 * @filp: The file to test lock for 2239 - * @fl: The lock to test; also used to hold result 2239 + * @fl: The byte-range in the file to test; also used to hold result 2240 2240 * 2241 + * On entry, @fl does not contain a lock, but identifies a range (fl_start, fl_end) 2242 + * in the file (c.flc_file), and an owner (c.flc_owner) for whom existing locks 2243 + * should be ignored. c.flc_type and c.flc_flags are ignored. 2244 + * Both fl_lmops and fl_ops in @fl must be NULL. 2241 2245 * Returns -ERRNO on failure. Indicates presence of conflicting lock by 2242 - * setting conf->fl_type to something other than F_UNLCK. 2246 + * setting fl->fl_type to something other than F_UNLCK. 2247 + * 2248 + * If vfs_test_lock() does find a lock and return it, the caller must 2249 + * use locks_free_lock() or locks_release_private() on the returned lock. 2243 2250 */ 2244 2251 int vfs_test_lock(struct file *filp, struct file_lock *fl) 2245 2252 { 2253 + WARN_ON_ONCE(fl->fl_ops || fl->fl_lmops); 2246 2254 WARN_ON_ONCE(filp != fl->c.flc_file); 2247 2255 if (filp->f_op->lock) 2248 2256 return filp->f_op->lock(filp, F_GETLK, fl);
+14 -6
fs/nfsd/nfs4state.c
··· 1218 1218 1219 1219 if (nf) 1220 1220 nfsd_file_put(nf); 1221 - if (rnf) 1221 + if (rnf) { 1222 + nfsd_file_put(rnf); 1222 1223 nfs4_file_put_access(fp, NFS4_SHARE_ACCESS_READ); 1224 + } 1223 1225 } 1224 1226 1225 1227 static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f) 1226 1228 { 1227 - struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME }; 1229 + struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME | ATTR_DELEG }; 1228 1230 struct inode *inode = file_inode(f); 1229 1231 int ret; 1230 1232 ··· 3099 3097 return -ENXIO; 3100 3098 3101 3099 ret = seq_open(file, &states_seq_ops); 3102 - if (ret) 3100 + if (ret) { 3101 + drop_client(clp); 3103 3102 return ret; 3103 + } 3104 3104 s = file->private_data; 3105 3105 s->private = clp; 3106 3106 return 0; ··· 6235 6231 fp = stp->st_stid.sc_file; 6236 6232 spin_lock(&fp->fi_lock); 6237 6233 __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); 6238 - fp = stp->st_stid.sc_file; 6239 - fp->fi_fds[O_RDONLY] = nf; 6240 - fp->fi_rdeleg_file = nf; 6234 + if (!fp->fi_fds[O_RDONLY]) { 6235 + fp->fi_fds[O_RDONLY] = nf; 6236 + nf = NULL; 6237 + } 6238 + fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); 6241 6239 spin_unlock(&fp->fi_lock); 6240 + if (nf) 6241 + nfsd_file_put(nf); 6242 6242 } 6243 6243 return true; 6244 6244 }