Skip to content

Commit f0b9d8e

Browse files
committed
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
2 parents 7f98ab9 + 0b88bfa commit f0b9d8e

11 files changed

Lines changed: 75 additions & 35 deletions

File tree

fs/nfs_common/common.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ static const struct {
1717
{ NFSERR_NOENT, -ENOENT },
1818
{ NFSERR_IO, -EIO },
1919
{ NFSERR_NXIO, -ENXIO },
20-
/* { NFSERR_EAGAIN, -EAGAIN }, */
2120
{ NFSERR_ACCES, -EACCES },
2221
{ NFSERR_EXIST, -EEXIST },
2322
{ NFSERR_XDEV, -EXDEV },

fs/nfsd/netns.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ struct nfsd_net {
6666

6767
struct lock_manager nfsd4_manager;
6868
bool grace_ended;
69+
bool grace_end_forced;
70+
bool client_tracking_active;
6971
time64_t boot_time;
7072

7173
struct dentry *nfsd_client_dir;

fs/nfsd/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
15021502
(schedule_timeout(20*HZ) == 0)) {
15031503
finish_wait(&nn->nfsd_ssc_waitq, &wait);
15041504
kfree(work);
1505-
return nfserr_eagain;
1505+
return nfserr_jukebox;
15061506
}
15071507
finish_wait(&nn->nfsd_ssc_waitq, &wait);
15081508
goto try_again;

fs/nfsd/nfs4state.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static u64 current_sessionid = 1;
8484
/* forward declarations */
8585
static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
8686
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);
8888
static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
8989
static void nfsd4_file_hash_remove(struct nfs4_file *fi);
9090
static void deleg_reaper(struct nfsd_net *nn);
@@ -1759,7 +1759,7 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp,
17591759

17601760
/**
17611761
* 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)
17631763
* @sb: super_block used to identify target filesystem
17641764
*
17651765
* All nfs4 states (open, lock, delegation, layout) held by the server instance
@@ -1771,16 +1771,15 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp,
17711771
* The clients which own the states will subsequently being notified that the
17721772
* states have been "admin-revoked".
17731773
*/
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)
17751775
{
1776-
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
17771776
unsigned int idhashval;
17781777
unsigned int sc_types;
17791778

17801779
sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT;
17811780

17821781
spin_lock(&nn->client_lock);
1783-
for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) {
1782+
for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) {
17841783
struct list_head *head = &nn->conf_id_hashtbl[idhashval];
17851784
struct nfs4_client *clp;
17861785
retry:
@@ -6570,7 +6569,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
65706569
return nfs_ok;
65716570
}
65726571

6573-
void
6572+
static void
65746573
nfsd4_end_grace(struct nfsd_net *nn)
65756574
{
65766575
/* do nothing if grace period already ended */
@@ -6603,6 +6602,33 @@ nfsd4_end_grace(struct nfsd_net *nn)
66036602
*/
66046603
}
66056604

6605+
/**
6606+
* nfsd4_force_end_grace - forcibly end the NFSv4 grace period
6607+
* @nn: network namespace for the server instance to be updated
6608+
*
6609+
* Forces bypass of normal grace period completion, then schedules
6610+
* the laundromat to end the grace period immediately. Does not wait
6611+
* for the grace period to fully terminate before returning.
6612+
*
6613+
* Return values:
6614+
* %true: Grace termination schedule
6615+
* %false: No action was taken
6616+
*/
6617+
bool nfsd4_force_end_grace(struct nfsd_net *nn)
6618+
{
6619+
if (!nn->client_tracking_ops)
6620+
return false;
6621+
spin_lock(&nn->client_lock);
6622+
if (nn->grace_ended || !nn->client_tracking_active) {
6623+
spin_unlock(&nn->client_lock);
6624+
return false;
6625+
}
6626+
WRITE_ONCE(nn->grace_end_forced, true);
6627+
mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
6628+
spin_unlock(&nn->client_lock);
6629+
return true;
6630+
}
6631+
66066632
/*
66076633
* If we've waited a lease period but there are still clients trying to
66086634
* reclaim, wait a little longer to give them a chance to finish.
@@ -6612,6 +6638,8 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
66126638
time64_t double_grace_period_end = nn->boot_time +
66136639
2 * nn->nfsd4_lease;
66146640

6641+
if (READ_ONCE(nn->grace_end_forced))
6642+
return false;
66156643
if (nn->track_reclaim_completes &&
66166644
atomic_read(&nn->nr_reclaim_complete) ==
66176645
nn->reclaim_str_hashtbl_size)
@@ -8932,6 +8960,8 @@ static int nfs4_state_create_net(struct net *net)
89328960
nn->unconf_name_tree = RB_ROOT;
89338961
nn->boot_time = ktime_get_real_seconds();
89348962
nn->grace_ended = false;
8963+
nn->grace_end_forced = false;
8964+
nn->client_tracking_active = false;
89358965
nn->nfsd4_manager.block_opens = true;
89368966
INIT_LIST_HEAD(&nn->nfsd4_manager.list);
89378967
INIT_LIST_HEAD(&nn->client_lru);
@@ -9012,6 +9042,10 @@ nfs4_state_start_net(struct net *net)
90129042
return ret;
90139043
locks_start_grace(net, &nn->nfsd4_manager);
90149044
nfsd4_client_tracking_init(net);
9045+
/* safe for laundromat to run now */
9046+
spin_lock(&nn->client_lock);
9047+
nn->client_tracking_active = true;
9048+
spin_unlock(&nn->client_lock);
90159049
if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
90169050
goto skip_grace;
90179051
printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
@@ -9060,6 +9094,9 @@ nfs4_state_shutdown_net(struct net *net)
90609094

90619095
shrinker_free(nn->nfsd_client_shrinker);
90629096
cancel_work_sync(&nn->nfsd_shrinker_work);
9097+
spin_lock(&nn->client_lock);
9098+
nn->client_tracking_active = false;
9099+
spin_unlock(&nn->client_lock);
90639100
cancel_delayed_work_sync(&nn->laundromat_work);
90649101
locks_end_grace(&nn->nfsd4_manager);
90659102

fs/nfsd/nfsctl.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
259259
struct path path;
260260
char *fo_path;
261261
int error;
262+
struct nfsd_net *nn;
262263

263264
/* sanity check */
264265
if (size == 0)
@@ -285,7 +286,13 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
285286
* 3. Is that directory the root of an exported file system?
286287
*/
287288
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
288-
nfsd4_revoke_states(netns(file), path.dentry->d_sb);
289+
mutex_lock(&nfsd_mutex);
290+
nn = net_generic(netns(file), nfsd_net_id);
291+
if (nn->nfsd_serv)
292+
nfsd4_revoke_states(nn, path.dentry->d_sb);
293+
else
294+
error = -EINVAL;
295+
mutex_unlock(&nfsd_mutex);
289296

290297
path_put(&path);
291298
return error;
@@ -1082,10 +1089,9 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
10821089
case 'Y':
10831090
case 'y':
10841091
case '1':
1085-
if (!nn->nfsd_serv)
1092+
if (!nfsd4_force_end_grace(nn))
10861093
return -EBUSY;
10871094
trace_nfsd_end_grace(netns(file));
1088-
nfsd4_end_grace(nn);
10891095
break;
10901096
default:
10911097
return -EINVAL;

fs/nfsd/nfsd.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ void nfsd_lockd_shutdown(void);
233233
#define nfserr_noent cpu_to_be32(NFSERR_NOENT)
234234
#define nfserr_io cpu_to_be32(NFSERR_IO)
235235
#define nfserr_nxio cpu_to_be32(NFSERR_NXIO)
236-
#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN)
237236
#define nfserr_acces cpu_to_be32(NFSERR_ACCES)
238237
#define nfserr_exist cpu_to_be32(NFSERR_EXIST)
239238
#define nfserr_xdev cpu_to_be32(NFSERR_XDEV)

fs/nfsd/nfssvc.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -406,26 +406,26 @@ static void nfsd_shutdown_net(struct net *net)
406406
{
407407
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
408408

409-
if (!nn->nfsd_net_up)
410-
return;
411-
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;
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);
412+
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);
422422
}
423423

424-
wait_for_completion(&nn->nfsd_net_free_done);
425424
percpu_ref_exit(&nn->nfsd_net_ref);
426425

426+
if (nn->nfsd_net_up)
427+
nfsd_shutdown_generic();
427428
nn->nfsd_net_up = false;
428-
nfsd_shutdown_generic();
429429
}
430430

431431
static DEFINE_SPINLOCK(nfsd_notifier_lock);

fs/nfsd/state.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -841,15 +841,15 @@ static inline void get_nfs4_file(struct nfs4_file *fi)
841841
struct nfsd_file *find_any_file(struct nfs4_file *f);
842842

843843
#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);
845845
#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)
847847
{
848848
}
849849
#endif
850850

851851
/* grace period management */
852-
void nfsd4_end_grace(struct nfsd_net *nn);
852+
bool nfsd4_force_end_grace(struct nfsd_net *nn);
853853

854854
/* nfs4recover operations */
855855
extern int nfsd4_client_tracking_init(struct net *net);

fs/nfsd/vfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2865,8 +2865,8 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
28652865

28662866
/* Allow read access to binaries even when mode 111 */
28672867
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))))
28702870
err = inode_permission(&nop_mnt_idmap, inode, MAY_EXEC);
28712871

28722872
return err? nfserrno(err) : 0;

include/trace/misc/nfs.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ TRACE_DEFINE_ENUM(NFSERR_PERM);
1616
TRACE_DEFINE_ENUM(NFSERR_NOENT);
1717
TRACE_DEFINE_ENUM(NFSERR_IO);
1818
TRACE_DEFINE_ENUM(NFSERR_NXIO);
19-
TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
2019
TRACE_DEFINE_ENUM(NFSERR_ACCES);
2120
TRACE_DEFINE_ENUM(NFSERR_EXIST);
2221
TRACE_DEFINE_ENUM(NFSERR_XDEV);
@@ -52,7 +51,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
5251
{ NFSERR_NXIO, "NXIO" }, \
5352
{ ECHILD, "CHILD" }, \
5453
{ ETIMEDOUT, "TIMEDOUT" }, \
55-
{ NFSERR_EAGAIN, "AGAIN" }, \
5654
{ NFSERR_ACCES, "ACCES" }, \
5755
{ NFSERR_EXIST, "EXIST" }, \
5856
{ NFSERR_XDEV, "XDEV" }, \

0 commit comments

Comments
 (0)