Skip to content

Commit

Permalink
NAS-132233 / 24.10.1 / merge upstream NFS-related fixes
Browse files Browse the repository at this point in the history
* nfsd: fix delegation_blocked() to block correctly for at least 30 seconds
* nfsd: return -EINVAL when namelen is 0
* nfsd: fix refcount leak when file is unhashed after being found
* SUNRPC: Fix a race to wake a sync task
* NFSv4: Add missing rescheduling points in nfs_client_return_marked_delegations
* nfs: fix memory leak in error path of nfs4_do_reclaim
* SUNRPC: Fix integer overflow in decode_rc_list()
* NFSv4: Prevent NULL-pointer dereference in nfs42_complete_copies()
* NFS: Avoid unnecessary rescanning of the per-server delegation list
* NFSD: Fix NFSv4's PUTPUBFH operation
* NFSD: simplify error paths in nfsd_svc()
  • Loading branch information
anodos325 authored Nov 20, 2024
2 parents ff82817 + e3191a7 commit de37033
Show file tree
Hide file tree
Showing 13 changed files with 34 additions and 34 deletions.
2 changes: 2 additions & 0 deletions fs/nfs/callback_xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ static __be32 decode_rc_list(struct xdr_stream *xdr,

rc_list->rcl_nrefcalls = ntohl(*p++);
if (rc_list->rcl_nrefcalls) {
if (unlikely(rc_list->rcl_nrefcalls > xdr->buf->len))
goto out;
p = xdr_inline_decode(xdr,
rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
if (unlikely(p == NULL))
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ struct nfs_server *nfs_alloc_server(void)
INIT_LIST_HEAD(&server->layouts);
INIT_LIST_HEAD(&server->state_owners_lru);
INIT_LIST_HEAD(&server->ss_copies);
INIT_LIST_HEAD(&server->ss_src_copies);

atomic_set(&server->active, 0);

Expand Down
15 changes: 5 additions & 10 deletions fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,9 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
prev = delegation;
continue;
}
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
continue;

if (prev) {
struct inode *tmp = nfs_delegation_grab_inode(prev);
Expand All @@ -637,12 +640,6 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
}
}

inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL) {
rcu_read_unlock();
iput(to_put);
goto restart;
}
delegation = nfs_start_delegation_return_locked(NFS_I(inode));
rcu_read_unlock();

Expand Down Expand Up @@ -1164,7 +1161,6 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
struct inode *inode;
restart:
rcu_read_lock();
restart_locked:
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_bit(NFS_DELEGATION_INODE_FREEING,
&delegation->flags) ||
Expand All @@ -1175,7 +1171,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
continue;
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
goto restart_locked;
continue;
delegation = nfs_start_delegation_return_locked(NFS_I(inode));
rcu_read_unlock();
if (delegation != NULL) {
Expand Down Expand Up @@ -1296,7 +1292,6 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
nfs4_stateid stateid;
restart:
rcu_read_lock();
restart_locked:
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_bit(NFS_DELEGATION_INODE_FREEING,
&delegation->flags) ||
Expand All @@ -1307,7 +1302,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
continue;
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
goto restart_locked;
continue;
spin_lock(&delegation->lock);
cred = get_cred_rcu(delegation->cred);
nfs4_stateid_copy(&stateid, &delegation->stateid);
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs42proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,

if (dst_server != src_server) {
spin_lock(&src_server->nfs_client->cl_lock);
list_add_tail(&copy->src_copies, &src_server->ss_copies);
list_add_tail(&copy->src_copies, &src_server->ss_src_copies);
spin_unlock(&src_server->nfs_client->cl_lock);
}

Expand Down
3 changes: 2 additions & 1 deletion fs/nfs/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1597,7 +1597,7 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state
complete(&copy->completion);
}
}
list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
list_for_each_entry(copy, &sp->so_server->ss_src_copies, src_copies) {
if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
!nfs4_stateid_match_other(&state->stateid,
&copy->parent_src_state->stateid)))
Expand Down Expand Up @@ -1957,6 +1957,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
set_bit(ops->owner_flag_bit, &sp->so_flags);
nfs4_put_state_owner(sp);
status = nfs4_recovery_handle_error(clp, status);
nfs4_free_state_owners(&freeme);
return (status != 0) ? status : -EAGAIN;
}

Expand Down
2 changes: 2 additions & 0 deletions fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <linux/vfs.h>
#include <linux/inet.h>
#include <linux/in6.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <net/ipv6.h>
#include <linux/netdevice.h>
Expand Down Expand Up @@ -223,6 +224,7 @@ static int __nfs_list_for_each_server(struct list_head *head,
ret = fn(server, data);
if (ret)
goto out;
cond_resched();
rcu_read_lock();
}
rcu_read_unlock();
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/filecache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
status = nfserr_jukebox;
goto construction_err;
}
nfsd_file_put(nf);
open_retry = false;
fh_put(fhp);
goto retry;
Expand Down
8 changes: 8 additions & 0 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,10 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
ci = &cmsg->cm_u.cm_clntinfo;
if (get_user(namelen, &ci->cc_name.cn_len))
return -EFAULT;
if (!namelen) {
dprintk("%s: namelen should not be zero", __func__);
return -EINVAL;
}
name.data = memdup_user(&ci->cc_name.cn_id, namelen);
if (IS_ERR(name.data))
return PTR_ERR(name.data);
Expand All @@ -828,6 +832,10 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
cnm = &cmsg->cm_u.cm_name;
if (get_user(namelen, &cnm->cn_len))
return -EFAULT;
if (!namelen) {
dprintk("%s: namelen should not be zero", __func__);
return -EINVAL;
}
name.data = memdup_user(&cnm->cn_id, namelen);
if (IS_ERR(name.data))
return PTR_ERR(name.data);
Expand Down
5 changes: 3 additions & 2 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,8 @@ static void nfs4_free_deleg(struct nfs4_stid *stid)
* When a delegation is recalled, the filehandle is stored in the "new"
* filter.
* Every 30 seconds we swap the filters and clear the "new" one,
* unless both are empty of course.
* unless both are empty of course. This results in delegations for a
* given filehandle being blocked for between 30 and 60 seconds.
*
* Each filter is 256 bits. We hash the filehandle to 32bit and use the
* low 3 bytes as hash-table indices.
Expand Down Expand Up @@ -1116,9 +1117,9 @@ static int delegation_blocked(struct knfsd_fh *fh)
if (ktime_get_seconds() - bd->swap_time > 30) {
bd->entries -= bd->old_entries;
bd->old_entries = bd->entries;
bd->new = 1-bd->new;
memset(bd->set[bd->new], 0,
sizeof(bd->set[0]));
bd->new = 1-bd->new;
bd->swap_time = ktime_get_seconds();
}
spin_unlock(&blocked_delegations_lock);
Expand Down
10 changes: 1 addition & 9 deletions fs/nfsd/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,14 +1287,6 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
return nfs_ok;
}

static __be32
nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
{
if (argp->minorversion == 0)
return nfs_ok;
return nfserr_notsupp;
}

static __be32
nfsd4_decode_read(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
Expand Down Expand Up @@ -2387,7 +2379,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
[OP_OPEN_CONFIRM] = nfsd4_decode_open_confirm,
[OP_OPEN_DOWNGRADE] = nfsd4_decode_open_downgrade,
[OP_PUTFH] = nfsd4_decode_putfh,
[OP_PUTPUBFH] = nfsd4_decode_putpubfh,
[OP_PUTPUBFH] = nfsd4_decode_noop,
[OP_PUTROOTFH] = nfsd4_decode_noop,
[OP_READ] = nfsd4_decode_read,
[OP_READDIR] = nfsd4_decode_readdir,
Expand Down
14 changes: 4 additions & 10 deletions fs/nfsd/nfssvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,6 @@ void nfsd_last_thread(struct net *net)
return;

nfsd_shutdown_net(net);
pr_info("nfsd: last server has exited, flushing export cache\n");
nfsd_export_flush(net);
}

Expand Down Expand Up @@ -787,7 +786,6 @@ int
nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
{
int error;
bool nfsd_up_before;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct svc_serv *serv;

Expand All @@ -807,26 +805,22 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
error = nfsd_create_serv(net);
if (error)
goto out;

nfsd_up_before = nn->nfsd_net_up;
serv = nn->nfsd_serv;

error = nfsd_startup_net(net, cred);
if (error)
goto out_put;
error = svc_set_num_threads(serv, NULL, nrservs);
if (error)
goto out_shutdown;
goto out_put;
error = serv->sv_nrthreads;
if (error == 0)
nfsd_last_thread(net);
out_shutdown:
if (error < 0 && !nfsd_up_before)
nfsd_shutdown_net(net);
out_put:
/* Threads now hold service active */
if (xchg(&nn->keep_active, 0))
svc_put(serv);

if (serv->sv_nrthreads == 0)
nfsd_last_thread(net);
svc_put(serv);
out:
mutex_unlock(&nfsd_mutex);
Expand Down
1 change: 1 addition & 0 deletions include/linux/nfs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ struct nfs_server {
struct list_head layouts;
struct list_head delegations;
struct list_head ss_copies;
struct list_head ss_src_copies;

unsigned long mig_gen;
unsigned long mig_status;
Expand Down
4 changes: 3 additions & 1 deletion net/sunrpc/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ static void rpc_make_runnable(struct workqueue_struct *wq,
if (RPC_IS_ASYNC(task)) {
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
queue_work(wq, &task->u.tk_work);
} else
} else {
smp_mb__after_atomic();
wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);
}
}

/*
Expand Down

0 comments on commit de37033

Please sign in to comment.