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

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

Pull nfsd fixes from Chuck Lever:
"A set of NFSD fixes for stable that arrived after the merge window:

- Remove an invalid NFS status code

- Fix an fstests failure when using pNFS

- Fix a UAF in v4_end_grace()

- Fix the administrative interface used to revoke NFSv4 state

- Fix a memory leak reported by syzbot"

* tag 'nfsd-6.19-3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
NFSD: net ref data still needs to be freed even if net hasn't startup
nfsd: check that server is running in unlock_filesystem
nfsd: use correct loop termination in nfsd4_revoke_states()
nfsd: provide locking for v4_end_grace
NFSD: Fix permission check for read access to executable-only files
NFSD: Remove NFSERR_EAGAIN

+74 -34
-1
fs/nfs_common/common.c
··· 17 17 { NFSERR_NOENT, -ENOENT }, 18 18 { NFSERR_IO, -EIO }, 19 19 { NFSERR_NXIO, -ENXIO }, 20 - /* { NFSERR_EAGAIN, -EAGAIN }, */ 21 20 { NFSERR_ACCES, -EACCES }, 22 21 { NFSERR_EXIST, -EEXIST }, 23 22 { NFSERR_XDEV, -EXDEV },
+2
fs/nfsd/netns.h
··· 66 66 67 67 struct lock_manager nfsd4_manager; 68 68 bool grace_ended; 69 + bool grace_end_forced; 70 + bool client_tracking_active; 69 71 time64_t boot_time; 70 72 71 73 struct dentry *nfsd_client_dir;
+1 -1
fs/nfsd/nfs4proc.c
··· 1502 1502 (schedule_timeout(20*HZ) == 0)) { 1503 1503 finish_wait(&nn->nfsd_ssc_waitq, &wait); 1504 1504 kfree(work); 1505 - return nfserr_eagain; 1505 + return nfserr_jukebox; 1506 1506 } 1507 1507 finish_wait(&nn->nfsd_ssc_waitq, &wait); 1508 1508 goto try_again;
+43 -6
fs/nfsd/nfs4state.c
··· 84 84 /* forward declarations */ 85 85 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 86 86 static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 87 - void nfsd4_end_grace(struct nfsd_net *nn); 87 + static void nfsd4_end_grace(struct nfsd_net *nn); 88 88 static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); 89 89 static void nfsd4_file_hash_remove(struct nfs4_file *fi); 90 90 static void deleg_reaper(struct nfsd_net *nn); ··· 1759 1759 1760 1760 /** 1761 1761 * nfsd4_revoke_states - revoke all nfsv4 states associated with given filesystem 1762 - * @net: used to identify instance of nfsd (there is one per net namespace) 1762 + * @nn: used to identify instance of nfsd (there is one per net namespace) 1763 1763 * @sb: super_block used to identify target filesystem 1764 1764 * 1765 1765 * All nfs4 states (open, lock, delegation, layout) held by the server instance ··· 1771 1771 * The clients which own the states will subsequently being notified that the 1772 1772 * states have been "admin-revoked". 1773 1773 */ 1774 - void nfsd4_revoke_states(struct net *net, struct super_block *sb) 1774 + void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) 1775 1775 { 1776 - struct nfsd_net *nn = net_generic(net, nfsd_net_id); 1777 1776 unsigned int idhashval; 1778 1777 unsigned int sc_types; 1779 1778 1780 1779 sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT; 1781 1780 1782 1781 spin_lock(&nn->client_lock); 1783 - for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { 1782 + for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) { 1784 1783 struct list_head *head = &nn->conf_id_hashtbl[idhashval]; 1785 1784 struct nfs4_client *clp; 1786 1785 retry: ··· 6569 6570 return nfs_ok; 6570 6571 } 6571 6572 6572 - void 6573 + static void 6573 6574 nfsd4_end_grace(struct nfsd_net *nn) 6574 6575 { 6575 6576 /* do nothing if grace period already ended */ ··· 6602 6603 */ 6603 6604 } 6604 6605 6606 + /** 6607 + * nfsd4_force_end_grace - forcibly end the NFSv4 grace period 6608 + * @nn: network namespace for the server instance to be updated 6609 + * 6610 + * Forces bypass of normal grace period completion, then schedules 6611 + * the laundromat to end the grace period immediately. Does not wait 6612 + * for the grace period to fully terminate before returning. 6613 + * 6614 + * Return values: 6615 + * %true: Grace termination schedule 6616 + * %false: No action was taken 6617 + */ 6618 + bool nfsd4_force_end_grace(struct nfsd_net *nn) 6619 + { 6620 + if (!nn->client_tracking_ops) 6621 + return false; 6622 + spin_lock(&nn->client_lock); 6623 + if (nn->grace_ended || !nn->client_tracking_active) { 6624 + spin_unlock(&nn->client_lock); 6625 + return false; 6626 + } 6627 + WRITE_ONCE(nn->grace_end_forced, true); 6628 + mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 6629 + spin_unlock(&nn->client_lock); 6630 + return true; 6631 + } 6632 + 6605 6633 /* 6606 6634 * If we've waited a lease period but there are still clients trying to 6607 6635 * reclaim, wait a little longer to give them a chance to finish. ··· 6638 6612 time64_t double_grace_period_end = nn->boot_time + 6639 6613 2 * nn->nfsd4_lease; 6640 6614 6615 + if (READ_ONCE(nn->grace_end_forced)) 6616 + return false; 6641 6617 if (nn->track_reclaim_completes && 6642 6618 atomic_read(&nn->nr_reclaim_complete) == 6643 6619 nn->reclaim_str_hashtbl_size) ··· 8960 8932 nn->unconf_name_tree = RB_ROOT; 8961 8933 nn->boot_time = ktime_get_real_seconds(); 8962 8934 nn->grace_ended = false; 8935 + nn->grace_end_forced = false; 8936 + nn->client_tracking_active = false; 8963 8937 nn->nfsd4_manager.block_opens = true; 8964 8938 INIT_LIST_HEAD(&nn->nfsd4_manager.list); 8965 8939 INIT_LIST_HEAD(&nn->client_lru); ··· 9042 9012 return ret; 9043 9013 locks_start_grace(net, &nn->nfsd4_manager); 9044 9014 nfsd4_client_tracking_init(net); 9015 + /* safe for laundromat to run now */ 9016 + spin_lock(&nn->client_lock); 9017 + nn->client_tracking_active = true; 9018 + spin_unlock(&nn->client_lock); 9045 9019 if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 9046 9020 goto skip_grace; 9047 9021 printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", ··· 9094 9060 9095 9061 shrinker_free(nn->nfsd_client_shrinker); 9096 9062 cancel_work_sync(&nn->nfsd_shrinker_work); 9063 + spin_lock(&nn->client_lock); 9064 + nn->client_tracking_active = false; 9065 + spin_unlock(&nn->client_lock); 9097 9066 cancel_delayed_work_sync(&nn->laundromat_work); 9098 9067 locks_end_grace(&nn->nfsd4_manager); 9099 9068
+9 -3
fs/nfsd/nfsctl.c
··· 259 259 struct path path; 260 260 char *fo_path; 261 261 int error; 262 + struct nfsd_net *nn; 262 263 263 264 /* sanity check */ 264 265 if (size == 0) ··· 286 285 * 3. Is that directory the root of an exported file system? 287 286 */ 288 287 error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); 289 - nfsd4_revoke_states(netns(file), path.dentry->d_sb); 288 + mutex_lock(&nfsd_mutex); 289 + nn = net_generic(netns(file), nfsd_net_id); 290 + if (nn->nfsd_serv) 291 + nfsd4_revoke_states(nn, path.dentry->d_sb); 292 + else 293 + error = -EINVAL; 294 + mutex_unlock(&nfsd_mutex); 290 295 291 296 path_put(&path); 292 297 return error; ··· 1089 1082 case 'Y': 1090 1083 case 'y': 1091 1084 case '1': 1092 - if (!nn->nfsd_serv) 1085 + if (!nfsd4_force_end_grace(nn)) 1093 1086 return -EBUSY; 1094 1087 trace_nfsd_end_grace(netns(file)); 1095 - nfsd4_end_grace(nn); 1096 1088 break; 1097 1089 default: 1098 1090 return -EINVAL;
-1
fs/nfsd/nfsd.h
··· 233 233 #define nfserr_noent cpu_to_be32(NFSERR_NOENT) 234 234 #define nfserr_io cpu_to_be32(NFSERR_IO) 235 235 #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) 236 - #define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) 237 236 #define nfserr_acces cpu_to_be32(NFSERR_ACCES) 238 237 #define nfserr_exist cpu_to_be32(NFSERR_EXIST) 239 238 #define nfserr_xdev cpu_to_be32(NFSERR_XDEV)
+14 -14
fs/nfsd/nfssvc.c
··· 406 406 { 407 407 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 408 408 409 - if (!nn->nfsd_net_up) 410 - return; 409 + if (nn->nfsd_net_up) { 410 + percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done); 411 + wait_for_completion(&nn->nfsd_net_confirm_done); 411 412 412 - percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done); 413 - wait_for_completion(&nn->nfsd_net_confirm_done); 414 - 415 - nfsd_export_flush(net); 416 - nfs4_state_shutdown_net(net); 417 - nfsd_reply_cache_shutdown(nn); 418 - nfsd_file_cache_shutdown_net(net); 419 - if (nn->lockd_up) { 420 - lockd_down(net); 421 - nn->lockd_up = false; 413 + nfsd_export_flush(net); 414 + nfs4_state_shutdown_net(net); 415 + nfsd_reply_cache_shutdown(nn); 416 + nfsd_file_cache_shutdown_net(net); 417 + if (nn->lockd_up) { 418 + lockd_down(net); 419 + nn->lockd_up = false; 420 + } 421 + wait_for_completion(&nn->nfsd_net_free_done); 422 422 } 423 423 424 - wait_for_completion(&nn->nfsd_net_free_done); 425 424 percpu_ref_exit(&nn->nfsd_net_ref); 426 425 426 + if (nn->nfsd_net_up) 427 + nfsd_shutdown_generic(); 427 428 nn->nfsd_net_up = false; 428 - nfsd_shutdown_generic(); 429 429 } 430 430 431 431 static DEFINE_SPINLOCK(nfsd_notifier_lock);
+3 -3
fs/nfsd/state.h
··· 841 841 struct nfsd_file *find_any_file(struct nfs4_file *f); 842 842 843 843 #ifdef CONFIG_NFSD_V4 844 - void nfsd4_revoke_states(struct net *net, struct super_block *sb); 844 + void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb); 845 845 #else 846 - static inline void nfsd4_revoke_states(struct net *net, struct super_block *sb) 846 + static inline void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) 847 847 { 848 848 } 849 849 #endif 850 850 851 851 /* grace period management */ 852 - void nfsd4_end_grace(struct nfsd_net *nn); 852 + bool nfsd4_force_end_grace(struct nfsd_net *nn); 853 853 854 854 /* nfs4recover operations */ 855 855 extern int nfsd4_client_tracking_init(struct net *net);
+2 -2
fs/nfsd/vfs.c
··· 2865 2865 2866 2866 /* Allow read access to binaries even when mode 111 */ 2867 2867 if (err == -EACCES && S_ISREG(inode->i_mode) && 2868 - (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || 2869 - acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) 2868 + (((acc & NFSD_MAY_MASK) == NFSD_MAY_READ) && 2869 + (acc & (NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_READ_IF_EXEC)))) 2870 2870 err = inode_permission(&nop_mnt_idmap, inode, MAY_EXEC); 2871 2871 2872 2872 return err? nfserrno(err) : 0;
-2
include/trace/misc/nfs.h
··· 16 16 TRACE_DEFINE_ENUM(NFSERR_NOENT); 17 17 TRACE_DEFINE_ENUM(NFSERR_IO); 18 18 TRACE_DEFINE_ENUM(NFSERR_NXIO); 19 - TRACE_DEFINE_ENUM(NFSERR_EAGAIN); 20 19 TRACE_DEFINE_ENUM(NFSERR_ACCES); 21 20 TRACE_DEFINE_ENUM(NFSERR_EXIST); 22 21 TRACE_DEFINE_ENUM(NFSERR_XDEV); ··· 51 52 { NFSERR_NXIO, "NXIO" }, \ 52 53 { ECHILD, "CHILD" }, \ 53 54 { ETIMEDOUT, "TIMEDOUT" }, \ 54 - { NFSERR_EAGAIN, "AGAIN" }, \ 55 55 { NFSERR_ACCES, "ACCES" }, \ 56 56 { NFSERR_EXIST, "EXIST" }, \ 57 57 { NFSERR_XDEV, "XDEV" }, \
-1
include/uapi/linux/nfs.h
··· 49 49 NFSERR_NOENT = 2, /* v2 v3 v4 */ 50 50 NFSERR_IO = 5, /* v2 v3 v4 */ 51 51 NFSERR_NXIO = 6, /* v2 v3 v4 */ 52 - NFSERR_EAGAIN = 11, /* v2 v3 */ 53 52 NFSERR_ACCES = 13, /* v2 v3 v4 */ 54 53 NFSERR_EXIST = 17, /* v2 v3 v4 */ 55 54 NFSERR_XDEV = 18, /* v3 v4 */