mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 09:00:12 +00:00
nfsd-6.19 fixes:
A set of NFSD fixes that arrived after the 6.19 merge window. Issues that need expedient stable backports: - 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmlb2WUACgkQM2qzM29m f5cqaA/+MbO1kop63/TiNE0tRc34yTBnApg1XVza4vSmcpSgpB8ZKGZ5xOjnRpwg yBw9+/puEJhyogPE6JKEGnLiFr+s3ApInFHaxnXnrGZz1RR1qkqfioKudIcpC0s1 /pKx7y/fktltgo/5Dl0gp2QH3Oytg375ge+dcSQbopSTQYPbsAw7AmoHDPBQd8Nr Q/pIu1q/tAM8R2zyijU3eAiUMyYRCrxNVYnlsdYmj7Dn0ypybOyKufkpVCEaS3kO a7SV/QSVKdNbZOf8annwAhW+VN4urFmA9nnnr/yirrLJ0i2h18E0txrPFBszhftf xpOvaDR7okfEvzqwrHvVfRsqB4nYq9f0TSvvpPsS8vCtq34pWKZPa6iiSxeVL/jb EmFtiesUWClZzTIQSpUdbuU80cST6WEoNJJKDPZwF1XbA2navsDqgxKiYxsczjt6 M5SStHcafK5LrXPruqOhfco/uKTmHNJJlvBWxUGCMQEDvdXdEJ4MIlg8VxxvoWPR FQDwU+iSdPOwlG7L3Tl9/PGSNe0MxJSgvzK6JNoKL3LvDx80FtMErWxPJdqdIL0+ RpBsW7zaCyX9lwD866Frs4K2H1w2XFeQjOMI0Pz1SG9dZ8NoKJ+lzcwVY7GgHUvq NUNJLzL6MVCHytwTfqrSY7PGvUCrDqR102FQusQyplT4edcUv0M= =okQh -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f0b9d8eb98
@ -17,7 +17,6 @@ static const struct {
|
||||
{ NFSERR_NOENT, -ENOENT },
|
||||
{ NFSERR_IO, -EIO },
|
||||
{ NFSERR_NXIO, -ENXIO },
|
||||
/* { NFSERR_EAGAIN, -EAGAIN }, */
|
||||
{ NFSERR_ACCES, -EACCES },
|
||||
{ NFSERR_EXIST, -EEXIST },
|
||||
{ NFSERR_XDEV, -EXDEV },
|
||||
|
||||
@ -66,6 +66,8 @@ struct nfsd_net {
|
||||
|
||||
struct lock_manager nfsd4_manager;
|
||||
bool grace_ended;
|
||||
bool grace_end_forced;
|
||||
bool client_tracking_active;
|
||||
time64_t boot_time;
|
||||
|
||||
struct dentry *nfsd_client_dir;
|
||||
|
||||
@ -1502,7 +1502,7 @@ try_again:
|
||||
(schedule_timeout(20*HZ) == 0)) {
|
||||
finish_wait(&nn->nfsd_ssc_waitq, &wait);
|
||||
kfree(work);
|
||||
return nfserr_eagain;
|
||||
return nfserr_jukebox;
|
||||
}
|
||||
finish_wait(&nn->nfsd_ssc_waitq, &wait);
|
||||
goto try_again;
|
||||
|
||||
@ -84,7 +84,7 @@ static u64 current_sessionid = 1;
|
||||
/* forward declarations */
|
||||
static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
|
||||
static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
|
||||
void nfsd4_end_grace(struct nfsd_net *nn);
|
||||
static void nfsd4_end_grace(struct nfsd_net *nn);
|
||||
static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
|
||||
static void nfsd4_file_hash_remove(struct nfs4_file *fi);
|
||||
static void deleg_reaper(struct nfsd_net *nn);
|
||||
@ -1759,7 +1759,7 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp,
|
||||
|
||||
/**
|
||||
* nfsd4_revoke_states - revoke all nfsv4 states associated with given filesystem
|
||||
* @net: used to identify instance of nfsd (there is one per net namespace)
|
||||
* @nn: used to identify instance of nfsd (there is one per net namespace)
|
||||
* @sb: super_block used to identify target filesystem
|
||||
*
|
||||
* 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,
|
||||
* The clients which own the states will subsequently being notified that the
|
||||
* states have been "admin-revoked".
|
||||
*/
|
||||
void nfsd4_revoke_states(struct net *net, struct super_block *sb)
|
||||
void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
unsigned int idhashval;
|
||||
unsigned int sc_types;
|
||||
|
||||
sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) {
|
||||
for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) {
|
||||
struct list_head *head = &nn->conf_id_hashtbl[idhashval];
|
||||
struct nfs4_client *clp;
|
||||
retry:
|
||||
@ -6570,7 +6569,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
nfsd4_end_grace(struct nfsd_net *nn)
|
||||
{
|
||||
/* do nothing if grace period already ended */
|
||||
@ -6603,6 +6602,33 @@ nfsd4_end_grace(struct nfsd_net *nn)
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd4_force_end_grace - forcibly end the NFSv4 grace period
|
||||
* @nn: network namespace for the server instance to be updated
|
||||
*
|
||||
* Forces bypass of normal grace period completion, then schedules
|
||||
* the laundromat to end the grace period immediately. Does not wait
|
||||
* for the grace period to fully terminate before returning.
|
||||
*
|
||||
* Return values:
|
||||
* %true: Grace termination schedule
|
||||
* %false: No action was taken
|
||||
*/
|
||||
bool nfsd4_force_end_grace(struct nfsd_net *nn)
|
||||
{
|
||||
if (!nn->client_tracking_ops)
|
||||
return false;
|
||||
spin_lock(&nn->client_lock);
|
||||
if (nn->grace_ended || !nn->client_tracking_active) {
|
||||
spin_unlock(&nn->client_lock);
|
||||
return false;
|
||||
}
|
||||
WRITE_ONCE(nn->grace_end_forced, true);
|
||||
mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've waited a lease period but there are still clients trying to
|
||||
* 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)
|
||||
time64_t double_grace_period_end = nn->boot_time +
|
||||
2 * nn->nfsd4_lease;
|
||||
|
||||
if (READ_ONCE(nn->grace_end_forced))
|
||||
return false;
|
||||
if (nn->track_reclaim_completes &&
|
||||
atomic_read(&nn->nr_reclaim_complete) ==
|
||||
nn->reclaim_str_hashtbl_size)
|
||||
@ -8932,6 +8960,8 @@ static int nfs4_state_create_net(struct net *net)
|
||||
nn->unconf_name_tree = RB_ROOT;
|
||||
nn->boot_time = ktime_get_real_seconds();
|
||||
nn->grace_ended = false;
|
||||
nn->grace_end_forced = false;
|
||||
nn->client_tracking_active = false;
|
||||
nn->nfsd4_manager.block_opens = true;
|
||||
INIT_LIST_HEAD(&nn->nfsd4_manager.list);
|
||||
INIT_LIST_HEAD(&nn->client_lru);
|
||||
@ -9012,6 +9042,10 @@ nfs4_state_start_net(struct net *net)
|
||||
return ret;
|
||||
locks_start_grace(net, &nn->nfsd4_manager);
|
||||
nfsd4_client_tracking_init(net);
|
||||
/* safe for laundromat to run now */
|
||||
spin_lock(&nn->client_lock);
|
||||
nn->client_tracking_active = true;
|
||||
spin_unlock(&nn->client_lock);
|
||||
if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
|
||||
goto skip_grace;
|
||||
printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
|
||||
@ -9060,6 +9094,9 @@ nfs4_state_shutdown_net(struct net *net)
|
||||
|
||||
shrinker_free(nn->nfsd_client_shrinker);
|
||||
cancel_work_sync(&nn->nfsd_shrinker_work);
|
||||
spin_lock(&nn->client_lock);
|
||||
nn->client_tracking_active = false;
|
||||
spin_unlock(&nn->client_lock);
|
||||
cancel_delayed_work_sync(&nn->laundromat_work);
|
||||
locks_end_grace(&nn->nfsd4_manager);
|
||||
|
||||
|
||||
@ -259,6 +259,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
struct path path;
|
||||
char *fo_path;
|
||||
int error;
|
||||
struct nfsd_net *nn;
|
||||
|
||||
/* sanity check */
|
||||
if (size == 0)
|
||||
@ -285,7 +286,13 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
* 3. Is that directory the root of an exported file system?
|
||||
*/
|
||||
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
|
||||
nfsd4_revoke_states(netns(file), path.dentry->d_sb);
|
||||
mutex_lock(&nfsd_mutex);
|
||||
nn = net_generic(netns(file), nfsd_net_id);
|
||||
if (nn->nfsd_serv)
|
||||
nfsd4_revoke_states(nn, path.dentry->d_sb);
|
||||
else
|
||||
error = -EINVAL;
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
|
||||
path_put(&path);
|
||||
return error;
|
||||
@ -1082,10 +1089,9 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
|
||||
case 'Y':
|
||||
case 'y':
|
||||
case '1':
|
||||
if (!nn->nfsd_serv)
|
||||
if (!nfsd4_force_end_grace(nn))
|
||||
return -EBUSY;
|
||||
trace_nfsd_end_grace(netns(file));
|
||||
nfsd4_end_grace(nn);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
@ -233,7 +233,6 @@ void nfsd_lockd_shutdown(void);
|
||||
#define nfserr_noent cpu_to_be32(NFSERR_NOENT)
|
||||
#define nfserr_io cpu_to_be32(NFSERR_IO)
|
||||
#define nfserr_nxio cpu_to_be32(NFSERR_NXIO)
|
||||
#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN)
|
||||
#define nfserr_acces cpu_to_be32(NFSERR_ACCES)
|
||||
#define nfserr_exist cpu_to_be32(NFSERR_EXIST)
|
||||
#define nfserr_xdev cpu_to_be32(NFSERR_XDEV)
|
||||
|
||||
@ -406,26 +406,26 @@ static void nfsd_shutdown_net(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (!nn->nfsd_net_up)
|
||||
return;
|
||||
if (nn->nfsd_net_up) {
|
||||
percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
|
||||
wait_for_completion(&nn->nfsd_net_confirm_done);
|
||||
|
||||
percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
|
||||
wait_for_completion(&nn->nfsd_net_confirm_done);
|
||||
|
||||
nfsd_export_flush(net);
|
||||
nfs4_state_shutdown_net(net);
|
||||
nfsd_reply_cache_shutdown(nn);
|
||||
nfsd_file_cache_shutdown_net(net);
|
||||
if (nn->lockd_up) {
|
||||
lockd_down(net);
|
||||
nn->lockd_up = false;
|
||||
nfsd_export_flush(net);
|
||||
nfs4_state_shutdown_net(net);
|
||||
nfsd_reply_cache_shutdown(nn);
|
||||
nfsd_file_cache_shutdown_net(net);
|
||||
if (nn->lockd_up) {
|
||||
lockd_down(net);
|
||||
nn->lockd_up = false;
|
||||
}
|
||||
wait_for_completion(&nn->nfsd_net_free_done);
|
||||
}
|
||||
|
||||
wait_for_completion(&nn->nfsd_net_free_done);
|
||||
percpu_ref_exit(&nn->nfsd_net_ref);
|
||||
|
||||
if (nn->nfsd_net_up)
|
||||
nfsd_shutdown_generic();
|
||||
nn->nfsd_net_up = false;
|
||||
nfsd_shutdown_generic();
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(nfsd_notifier_lock);
|
||||
|
||||
@ -841,15 +841,15 @@ static inline void get_nfs4_file(struct nfs4_file *fi)
|
||||
struct nfsd_file *find_any_file(struct nfs4_file *f);
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
void nfsd4_revoke_states(struct net *net, struct super_block *sb);
|
||||
void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb);
|
||||
#else
|
||||
static inline void nfsd4_revoke_states(struct net *net, struct super_block *sb)
|
||||
static inline void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* grace period management */
|
||||
void nfsd4_end_grace(struct nfsd_net *nn);
|
||||
bool nfsd4_force_end_grace(struct nfsd_net *nn);
|
||||
|
||||
/* nfs4recover operations */
|
||||
extern int nfsd4_client_tracking_init(struct net *net);
|
||||
|
||||
@ -2865,8 +2865,8 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
|
||||
|
||||
/* Allow read access to binaries even when mode 111 */
|
||||
if (err == -EACCES && S_ISREG(inode->i_mode) &&
|
||||
(acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
|
||||
acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
|
||||
(((acc & NFSD_MAY_MASK) == NFSD_MAY_READ) &&
|
||||
(acc & (NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_READ_IF_EXEC))))
|
||||
err = inode_permission(&nop_mnt_idmap, inode, MAY_EXEC);
|
||||
|
||||
return err? nfserrno(err) : 0;
|
||||
|
||||
@ -16,7 +16,6 @@ TRACE_DEFINE_ENUM(NFSERR_PERM);
|
||||
TRACE_DEFINE_ENUM(NFSERR_NOENT);
|
||||
TRACE_DEFINE_ENUM(NFSERR_IO);
|
||||
TRACE_DEFINE_ENUM(NFSERR_NXIO);
|
||||
TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
|
||||
TRACE_DEFINE_ENUM(NFSERR_ACCES);
|
||||
TRACE_DEFINE_ENUM(NFSERR_EXIST);
|
||||
TRACE_DEFINE_ENUM(NFSERR_XDEV);
|
||||
@ -52,7 +51,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
|
||||
{ NFSERR_NXIO, "NXIO" }, \
|
||||
{ ECHILD, "CHILD" }, \
|
||||
{ ETIMEDOUT, "TIMEDOUT" }, \
|
||||
{ NFSERR_EAGAIN, "AGAIN" }, \
|
||||
{ NFSERR_ACCES, "ACCES" }, \
|
||||
{ NFSERR_EXIST, "EXIST" }, \
|
||||
{ NFSERR_XDEV, "XDEV" }, \
|
||||
|
||||
@ -49,7 +49,6 @@
|
||||
NFSERR_NOENT = 2, /* v2 v3 v4 */
|
||||
NFSERR_IO = 5, /* v2 v3 v4 */
|
||||
NFSERR_NXIO = 6, /* v2 v3 v4 */
|
||||
NFSERR_EAGAIN = 11, /* v2 v3 */
|
||||
NFSERR_ACCES = 13, /* v2 v3 v4 */
|
||||
NFSERR_EXIST = 17, /* v2 v3 v4 */
|
||||
NFSERR_XDEV = 18, /* v3 v4 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user