Skip to content

Commit

Permalink
Merge tag 'nfsd-5.5' of git://linux-nfs.org/~bfields/linux
Browse files Browse the repository at this point in the history
Pull nfsd updates from Bruce Fields:
 "This is a relatively quiet cycle for nfsd, mainly various bugfixes.

  Possibly most interesting is Trond's fixes for some callback races
  that were due to my incomplete understanding of rpc client shutdown.
  Unfortunately at the last minute I've started noticing a new
  intermittent failure to send callbacks. As the logic seems basically
  correct, I'm leaving Trond's patches in for now, and hope to find a
  fix in the next week so I don't have to revert those patches"

* tag 'nfsd-5.5' of git://linux-nfs.org/~bfields/linux: (24 commits)
  nfsd: depend on CRYPTO_MD5 for legacy client tracking
  NFSD fixing possible null pointer derefering in copy offload
  nfsd: check for EBUSY from vfs_rmdir/vfs_unink.
  nfsd: Ensure CLONE persists data and metadata changes to the target file
  SUNRPC: Fix backchannel latency metrics
  nfsd: restore NFSv3 ACL support
  nfsd: v4 support requires CRYPTO_SHA256
  nfsd: Fix cld_net->cn_tfm initialization
  lockd: remove __KERNEL__ ifdefs
  sunrpc: remove __KERNEL__ ifdefs
  race in exportfs_decode_fh()
  nfsd: Drop LIST_HEAD where the variable it declares is never used.
  nfsd: document callback_wq serialization of callback code
  nfsd: mark cb path down on unknown errors
  nfsd: Fix races between nfsd4_cb_release() and nfsd4_shutdown_callback()
  nfsd: minor 4.1 callback cleanup
  SUNRPC: Fix svcauth_gss_proxy_init()
  SUNRPC: Trace gssproxy upcall results
  sunrpc: fix crash when cache_head become valid before update
  nfsd: remove private bin2hex implementation
  ...
  • Loading branch information
torvalds committed Dec 8, 2019
2 parents fb9bf40 + 38a2204 commit 911d137
Show file tree
Hide file tree
Showing 37 changed files with 343 additions and 137 deletions.
3 changes: 2 additions & 1 deletion fs/nfsd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ config NFSD_V4
select NFSD_V3
select FS_POSIX_ACL
select SUNRPC_GSS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_SHA256
select GRACE_PERIOD
help
This option enables support in your system's NFS server for
Expand Down
2 changes: 0 additions & 2 deletions fs/nfsd/filecache.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,6 @@ nfsd_file_cache_purge(struct net *net)
void
nfsd_file_cache_shutdown(void)
{
LIST_HEAD(dispose);

set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);

lease_unregister_notifier(&nfsd_file_lease_notifier);
Expand Down
104 changes: 85 additions & 19 deletions fs/nfsd/nfs4callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,31 @@ static int max_cb_time(struct net *net)
return max(nn->nfsd4_lease/10, (time_t)1) * HZ;
}

static struct workqueue_struct *callback_wq;

static bool nfsd4_queue_cb(struct nfsd4_callback *cb)
{
return queue_work(callback_wq, &cb->cb_work);
}

static void nfsd41_cb_inflight_begin(struct nfs4_client *clp)
{
atomic_inc(&clp->cl_cb_inflight);
}

static void nfsd41_cb_inflight_end(struct nfs4_client *clp)
{

if (atomic_dec_and_test(&clp->cl_cb_inflight))
wake_up_var(&clp->cl_cb_inflight);
}

static void nfsd41_cb_inflight_wait_complete(struct nfs4_client *clp)
{
wait_var_event(&clp->cl_cb_inflight,
!atomic_read(&clp->cl_cb_inflight));
}

static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
{
if (clp->cl_minorversion == 0) {
Expand Down Expand Up @@ -937,14 +962,21 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
clp->cl_cb_state = NFSD4_CB_UP;
}

static void nfsd4_cb_probe_release(void *calldata)
{
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);

nfsd41_cb_inflight_end(clp);

}

static const struct rpc_call_ops nfsd4_cb_probe_ops = {
/* XXX: release method to ensure we set the cb channel down if
* necessary on early failure? */
.rpc_call_done = nfsd4_cb_probe_done,
.rpc_release = nfsd4_cb_probe_release,
};

static struct workqueue_struct *callback_wq;

/*
* Poke the callback thread to process any updates to the callback
* parameters, and send a null probe.
Expand Down Expand Up @@ -975,9 +1007,12 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
* If the slot is available, then mark it busy. Otherwise, set the
* thread for sleeping on the callback RPC wait queue.
*/
static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
static bool nfsd41_cb_get_slot(struct nfsd4_callback *cb, struct rpc_task *task)
{
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
struct nfs4_client *clp = cb->cb_clp;

if (!cb->cb_holds_slot &&
test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
/* Race breaker */
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
Expand All @@ -986,9 +1021,31 @@ static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
}
rpc_wake_up_queued_task(&clp->cl_cb_waitq, task);
}
cb->cb_holds_slot = true;
return true;
}

static void nfsd41_cb_release_slot(struct nfsd4_callback *cb)
{
struct nfs4_client *clp = cb->cb_clp;

if (cb->cb_holds_slot) {
cb->cb_holds_slot = false;
clear_bit(0, &clp->cl_cb_slot_busy);
rpc_wake_up_next(&clp->cl_cb_waitq);
}
}

static void nfsd41_destroy_cb(struct nfsd4_callback *cb)
{
struct nfs4_client *clp = cb->cb_clp;

nfsd41_cb_release_slot(cb);
if (cb->cb_ops && cb->cb_ops->release)
cb->cb_ops->release(cb);
nfsd41_cb_inflight_end(clp);
}

/*
* TODO: cb_sequence should support referring call lists, cachethis, multiple
* slots, and mark callback channel down on communication errors.
Expand All @@ -1005,11 +1062,8 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
*/
cb->cb_seq_status = 1;
cb->cb_status = 0;
if (minorversion) {
if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task))
return;
cb->cb_holds_slot = true;
}
if (minorversion && !nfsd41_cb_get_slot(cb, task))
return;
rpc_call_start(task);
}

Expand Down Expand Up @@ -1072,13 +1126,12 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
}
break;
default:
nfsd4_mark_cb_fault(cb->cb_clp, cb->cb_seq_status);
dprintk("%s: unprocessed error %d\n", __func__,
cb->cb_seq_status);
}

cb->cb_holds_slot = false;
clear_bit(0, &clp->cl_cb_slot_busy);
rpc_wake_up_next(&clp->cl_cb_waitq);
nfsd41_cb_release_slot(cb);
dprintk("%s: freed slot, new seqid=%d\n", __func__,
clp->cl_cb_session->se_cb_seq_nr);

Expand All @@ -1091,8 +1144,10 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
ret = false;
goto out;
need_restart:
task->tk_status = 0;
cb->cb_need_restart = true;
if (!test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags)) {
task->tk_status = 0;
cb->cb_need_restart = true;
}
return false;
}

Expand Down Expand Up @@ -1134,9 +1189,9 @@ static void nfsd4_cb_release(void *calldata)
struct nfsd4_callback *cb = calldata;

if (cb->cb_need_restart)
nfsd4_run_cb(cb);
nfsd4_queue_cb(cb);
else
cb->cb_ops->release(cb);
nfsd41_destroy_cb(cb);

}

Expand Down Expand Up @@ -1170,6 +1225,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
*/
nfsd4_run_cb(&clp->cl_cb_null);
flush_workqueue(callback_wq);
nfsd41_cb_inflight_wait_complete(clp);
}

/* requires cl_lock: */
Expand All @@ -1187,6 +1243,12 @@ static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
return NULL;
}

/*
* Note there isn't a lot of locking in this code; instead we depend on
* the fact that it is run from the callback_wq, which won't run two
* work items at once. So, for example, callback_wq handles all access
* of cl_cb_client and all calls to rpc_create or rpc_shutdown_client.
*/
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
{
struct nfs4_cb_conn conn;
Expand Down Expand Up @@ -1255,8 +1317,7 @@ nfsd4_run_cb_work(struct work_struct *work)
clnt = clp->cl_cb_client;
if (!clnt) {
/* Callback channel broken, or client killed; give up: */
if (cb->cb_ops && cb->cb_ops->release)
cb->cb_ops->release(cb);
nfsd41_destroy_cb(cb);
return;
}

Expand All @@ -1265,6 +1326,7 @@ nfsd4_run_cb_work(struct work_struct *work)
*/
if (!cb->cb_ops && clp->cl_minorversion) {
clp->cl_cb_state = NFSD4_CB_UP;
nfsd41_destroy_cb(cb);
return;
}

Expand All @@ -1290,5 +1352,9 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,

void nfsd4_run_cb(struct nfsd4_callback *cb)
{
queue_work(callback_wq, &cb->cb_work);
struct nfs4_client *clp = cb->cb_clp;

nfsd41_cb_inflight_begin(clp);
if (!nfsd4_queue_cb(cb))
nfsd41_cb_inflight_end(clp);
}
6 changes: 4 additions & 2 deletions fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,8 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;

status = nfsd4_clone_file_range(src->nf_file, clone->cl_src_pos,
dst->nf_file, clone->cl_dst_pos, clone->cl_count);
dst->nf_file, clone->cl_dst_pos, clone->cl_count,
EX_ISSYNC(cstate->current_fh.fh_export));

nfsd_file_put(dst);
nfsd_file_put(src);
Expand Down Expand Up @@ -1297,7 +1298,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
out:
return status;
out_err:
cleanup_async_copy(async_copy);
if (async_copy)
cleanup_async_copy(async_copy);
goto out;
}

Expand Down
23 changes: 10 additions & 13 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,7 @@ nfsd4_cld_tracking_init(struct net *net)
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
bool running;
int retries = 10;
struct crypto_shash *tfm;

status = nfs4_cld_state_init(net);
if (status)
Expand All @@ -1586,11 +1587,6 @@ nfsd4_cld_tracking_init(struct net *net)
status = __nfsd4_init_cld_pipe(net);
if (status)
goto err_shutdown;
nn->cld_net->cn_tfm = crypto_alloc_shash("sha256", 0, 0);
if (IS_ERR(nn->cld_net->cn_tfm)) {
status = PTR_ERR(nn->cld_net->cn_tfm);
goto err_remove;
}

/*
* rpc pipe upcalls take 30 seconds to time out, so we don't want to
Expand All @@ -1607,6 +1603,12 @@ nfsd4_cld_tracking_init(struct net *net)
status = -ETIMEDOUT;
goto err_remove;
}
tfm = crypto_alloc_shash("sha256", 0, 0);
if (IS_ERR(tfm)) {
status = PTR_ERR(tfm);
goto err_remove;
}
nn->cld_net->cn_tfm = tfm;

status = nfsd4_cld_get_version(nn);
if (status == -EOPNOTSUPP)
Expand Down Expand Up @@ -1850,19 +1852,14 @@ nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *env0, char *env1)
static char *
bin_to_hex_dup(const unsigned char *src, int srclen)
{
int i;
char *buf, *hex;
char *buf;

/* +1 for terminating NULL */
buf = kmalloc((srclen * 2) + 1, GFP_KERNEL);
buf = kzalloc((srclen * 2) + 1, GFP_KERNEL);
if (!buf)
return buf;

hex = buf;
for (i = 0; i < srclen; i++) {
sprintf(hex, "%2.2x", *src++);
hex += 2;
}
bin2hex(buf, src, srclen);
return buf;
}

Expand Down
19 changes: 12 additions & 7 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -2382,10 +2382,10 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
access = bmap_to_share_mode(ols->st_access_bmap);
deny = bmap_to_share_mode(ols->st_deny_bmap);

seq_printf(s, "access: \%s\%s, ",
seq_printf(s, "access: %s%s, ",
access & NFS4_SHARE_ACCESS_READ ? "r" : "-",
access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-");
seq_printf(s, "deny: \%s\%s, ",
seq_printf(s, "deny: %s%s, ",
deny & NFS4_SHARE_ACCESS_READ ? "r" : "-",
deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-");

Expand Down Expand Up @@ -3548,12 +3548,17 @@ static bool replay_matches_cache(struct svc_rqst *rqstp,
(bool)seq->cachethis)
return false;
/*
* If there's an error than the reply can have fewer ops than
* the call. But if we cached a reply with *more* ops than the
* call you're sending us now, then this new call is clearly not
* really a replay of the old one:
* If there's an error then the reply can have fewer ops than
* the call.
*/
if (slot->sl_opcnt < argp->opcnt)
if (slot->sl_opcnt < argp->opcnt && !slot->sl_status)
return false;
/*
* But if we cached a reply with *more* ops than the call you're
* sending us now, then this new call is clearly not really a
* replay of the old one:
*/
if (slot->sl_opcnt > argp->opcnt)
return false;
/* This is the only check explicitly called by spec: */
if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
Expand Down
2 changes: 0 additions & 2 deletions fs/nfsd/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3452,7 +3452,6 @@ static __be32 nfsd4_encode_splice_read(
struct xdr_stream *xdr = &resp->xdr;
struct xdr_buf *buf = xdr->buf;
u32 eof;
long len;
int space_left;
__be32 nfserr;
__be32 *p = xdr->p - 2;
Expand All @@ -3461,7 +3460,6 @@ static __be32 nfsd4_encode_splice_read(
if (xdr->end - xdr->p < 1)
return nfserr_resource;

len = maxcount;
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
file, read->rd_offset, &maxcount, &eof);
read->rd_length = maxcount;
Expand Down
3 changes: 2 additions & 1 deletion fs/nfsd/nfsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ void nfsd_lockd_shutdown(void);
#define nfserr_union_notsupp cpu_to_be32(NFS4ERR_UNION_NOTSUPP)
#define nfserr_offload_denied cpu_to_be32(NFS4ERR_OFFLOAD_DENIED)
#define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS)
#define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL)
#define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL)
#define nfserr_file_open cpu_to_be32(NFS4ERR_FILE_OPEN)

/* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped.
Expand Down
3 changes: 1 addition & 2 deletions fs/nfsd/nfssvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,11 @@ static const struct svc_version *nfsd_acl_version[] = {

#define NFSD_ACL_MINVERS 2
#define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version)
static const struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];

static struct svc_program nfsd_acl_program = {
.pg_prog = NFS_ACL_PROGRAM,
.pg_nvers = NFSD_ACL_NRVERS,
.pg_vers = nfsd_acl_versions,
.pg_vers = nfsd_acl_version,
.pg_name = "nfsacl",
.pg_class = "nfsd",
.pg_stats = &nfsd_acl_svcstats,
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ struct nfs4_client {
struct net *net;
struct list_head async_copies; /* list of async copies */
spinlock_t async_lock; /* lock for async copies */
atomic_t cl_cb_inflight; /* Outstanding callbacks */
};

/* struct nfs4_client_reset
Expand Down
Loading

0 comments on commit 911d137

Please sign in to comment.