Commit 0cf21c66 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-4.8-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable patches:
   - Fix a refcount leak in nfs_callback_up_net
   - Fix an Oopsable condition when the flexfile pNFS driver connection
     to the DS fails
   - Fix an Oopsable condition in NFSv4.1 server callback races
   - Ensure pNFS clients stop doing I/O to the DS if their lease has
     expired, as required by the NFSv4.1 protocol

  Bugfixes:
   - Fix potential looping in the NFSv4.x migration code
   - Patch series to close callback races for OPEN, LAYOUTGET and
     LAYOUTRETURN
   - Silence WARN_ON when NFSv4.1 over RDMA is in use
   - Fix a LAYOUTCOMMIT race in the pNFS/blocks client
   - Fix pNFS timeout issues when the DS fails"

* tag 'nfs-for-4.8-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4.x: Fix a refcount leak in nfs_callback_up_net
  NFS4: Avoid migration loops
  pNFS/flexfiles: Fix an Oopsable condition when connection to the DS fails
  NFSv4.1: Remove obsolete and incorrrect assignment in nfs4_callback_sequence
  NFSv4.1: Close callback races for OPEN, LAYOUTGET and LAYOUTRETURN
  NFSv4.1: Defer bumping the slot sequence number until we free the slot
  NFSv4.1: Delay callback processing when there are referring triples
  NFSv4.1: Fix Oopsable condition in server callback races
  SUNRPC: Silence WARN_ON when NFSv4.1 over RDMA is in use
  pnfs/blocklayout: update last_write_offset atomically with extents
  pNFS: The client must not do I/O to the DS if it's lease has expired
  pNFS: Handle NFS4ERR_OLD_STATEID correctly in LAYOUTSTAT calls
  pNFS/flexfiles: Set reasonable default retrans values for the data channel
  NFS: Allow the mount option retrans=0
  pNFS/flexfiles: Fix layoutstat periodic reporting
parents 0d025d27 98b0f80c
...@@ -346,7 +346,7 @@ static void bl_write_cleanup(struct work_struct *work) ...@@ -346,7 +346,7 @@ static void bl_write_cleanup(struct work_struct *work)
PAGE_SIZE - 1) & (loff_t)PAGE_MASK; PAGE_SIZE - 1) & (loff_t)PAGE_MASK;
ext_tree_mark_written(bl, start >> SECTOR_SHIFT, ext_tree_mark_written(bl, start >> SECTOR_SHIFT,
(end - start) >> SECTOR_SHIFT); (end - start) >> SECTOR_SHIFT, end);
} }
pnfs_ld_write_done(hdr); pnfs_ld_write_done(hdr);
......
...@@ -141,6 +141,7 @@ struct pnfs_block_layout { ...@@ -141,6 +141,7 @@ struct pnfs_block_layout {
struct rb_root bl_ext_ro; struct rb_root bl_ext_ro;
spinlock_t bl_ext_lock; /* Protects list manipulation */ spinlock_t bl_ext_lock; /* Protects list manipulation */
bool bl_scsi_layout; bool bl_scsi_layout;
u64 bl_lwb;
}; };
static inline struct pnfs_block_layout * static inline struct pnfs_block_layout *
...@@ -182,7 +183,7 @@ int ext_tree_insert(struct pnfs_block_layout *bl, ...@@ -182,7 +183,7 @@ int ext_tree_insert(struct pnfs_block_layout *bl,
int ext_tree_remove(struct pnfs_block_layout *bl, bool rw, sector_t start, int ext_tree_remove(struct pnfs_block_layout *bl, bool rw, sector_t start,
sector_t end); sector_t end);
int ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, int ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
sector_t len); sector_t len, u64 lwb);
bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect, bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
struct pnfs_block_extent *ret, bool rw); struct pnfs_block_extent *ret, bool rw);
int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg);
......
...@@ -402,7 +402,7 @@ ext_tree_split(struct rb_root *root, struct pnfs_block_extent *be, ...@@ -402,7 +402,7 @@ ext_tree_split(struct rb_root *root, struct pnfs_block_extent *be,
int int
ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
sector_t len) sector_t len, u64 lwb)
{ {
struct rb_root *root = &bl->bl_ext_rw; struct rb_root *root = &bl->bl_ext_rw;
sector_t end = start + len; sector_t end = start + len;
...@@ -471,6 +471,8 @@ ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, ...@@ -471,6 +471,8 @@ ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
} }
} }
out: out:
if (bl->bl_lwb < lwb)
bl->bl_lwb = lwb;
spin_unlock(&bl->bl_ext_lock); spin_unlock(&bl->bl_ext_lock);
__ext_put_deviceids(&tmp); __ext_put_deviceids(&tmp);
...@@ -518,7 +520,7 @@ static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p) ...@@ -518,7 +520,7 @@ static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
} }
static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p, static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
size_t buffer_size, size_t *count) size_t buffer_size, size_t *count, __u64 *lastbyte)
{ {
struct pnfs_block_extent *be; struct pnfs_block_extent *be;
int ret = 0; int ret = 0;
...@@ -542,6 +544,8 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p, ...@@ -542,6 +544,8 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
p = encode_block_extent(be, p); p = encode_block_extent(be, p);
be->be_tag = EXTENT_COMMITTING; be->be_tag = EXTENT_COMMITTING;
} }
*lastbyte = bl->bl_lwb - 1;
bl->bl_lwb = 0;
spin_unlock(&bl->bl_ext_lock); spin_unlock(&bl->bl_ext_lock);
return ret; return ret;
...@@ -564,7 +568,7 @@ ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg) ...@@ -564,7 +568,7 @@ ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
arg->layoutupdate_pages = &arg->layoutupdate_page; arg->layoutupdate_pages = &arg->layoutupdate_page;
retry: retry:
ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count); ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten);
if (unlikely(ret)) { if (unlikely(ret)) {
ext_tree_free_commitdata(arg, buffer_size); ext_tree_free_commitdata(arg, buffer_size);
......
...@@ -275,6 +275,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, ...@@ -275,6 +275,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
err_socks: err_socks:
svc_rpcb_cleanup(serv, net); svc_rpcb_cleanup(serv, net);
err_bind: err_bind:
nn->cb_users[minorversion]--;
dprintk("NFS: Couldn't create callback socket: err = %d; " dprintk("NFS: Couldn't create callback socket: err = %d; "
"net = %p\n", ret, net); "net = %p\n", ret, net);
return ret; return ret;
......
...@@ -454,11 +454,8 @@ static bool referring_call_exists(struct nfs_client *clp, ...@@ -454,11 +454,8 @@ static bool referring_call_exists(struct nfs_client *clp,
((u32 *)&rclist->rcl_sessionid.data)[3], ((u32 *)&rclist->rcl_sessionid.data)[3],
ref->rc_sequenceid, ref->rc_slotid); ref->rc_sequenceid, ref->rc_slotid);
spin_lock(&tbl->slot_tbl_lock); status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid,
status = (test_bit(ref->rc_slotid, tbl->used_slots) && ref->rc_sequenceid, HZ >> 1) < 0;
tbl->slots[ref->rc_slotid].seq_nr ==
ref->rc_sequenceid);
spin_unlock(&tbl->slot_tbl_lock);
if (status) if (status)
goto out; goto out;
} }
...@@ -487,7 +484,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, ...@@ -487,7 +484,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
goto out; goto out;
tbl = &clp->cl_session->bc_slot_table; tbl = &clp->cl_session->bc_slot_table;
slot = tbl->slots + args->csa_slotid;
/* Set up res before grabbing the spinlock */ /* Set up res before grabbing the spinlock */
memcpy(&res->csr_sessionid, &args->csa_sessionid, memcpy(&res->csr_sessionid, &args->csa_sessionid,
......
...@@ -426,7 +426,7 @@ EXPORT_SYMBOL_GPL(nfs_mark_client_ready); ...@@ -426,7 +426,7 @@ EXPORT_SYMBOL_GPL(nfs_mark_client_ready);
* Initialise the timeout values for a connection * Initialise the timeout values for a connection
*/ */
void nfs_init_timeout_values(struct rpc_timeout *to, int proto, void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
unsigned int timeo, unsigned int retrans) int timeo, int retrans)
{ {
to->to_initval = timeo * HZ / 10; to->to_initval = timeo * HZ / 10;
to->to_retries = retrans; to->to_retries = retrans;
...@@ -434,9 +434,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto, ...@@ -434,9 +434,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
switch (proto) { switch (proto) {
case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA: case XPRT_TRANSPORT_RDMA:
if (to->to_retries == 0) if (retrans == NFS_UNSPEC_RETRANS)
to->to_retries = NFS_DEF_TCP_RETRANS; to->to_retries = NFS_DEF_TCP_RETRANS;
if (to->to_initval == 0) if (timeo == NFS_UNSPEC_TIMEO || to->to_retries == 0)
to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10; to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_TCP_TIMEOUT) if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
to->to_initval = NFS_MAX_TCP_TIMEOUT; to->to_initval = NFS_MAX_TCP_TIMEOUT;
...@@ -449,9 +449,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto, ...@@ -449,9 +449,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_exponential = 0; to->to_exponential = 0;
break; break;
case XPRT_TRANSPORT_UDP: case XPRT_TRANSPORT_UDP:
if (to->to_retries == 0) if (retrans == NFS_UNSPEC_RETRANS)
to->to_retries = NFS_DEF_UDP_RETRANS; to->to_retries = NFS_DEF_UDP_RETRANS;
if (!to->to_initval) if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0)
to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10; to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_UDP_TIMEOUT) if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
to->to_initval = NFS_MAX_UDP_TIMEOUT; to->to_initval = NFS_MAX_UDP_TIMEOUT;
......
...@@ -37,6 +37,7 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) ...@@ -37,6 +37,7 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
if (ffl) { if (ffl) {
INIT_LIST_HEAD(&ffl->error_list); INIT_LIST_HEAD(&ffl->error_list);
INIT_LIST_HEAD(&ffl->mirrors); INIT_LIST_HEAD(&ffl->mirrors);
ffl->last_report_time = ktime_get();
return &ffl->generic_hdr; return &ffl->generic_hdr;
} else } else
return NULL; return NULL;
...@@ -640,19 +641,18 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror, ...@@ -640,19 +641,18 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror,
{ {
static const ktime_t notime = {0}; static const ktime_t notime = {0};
s64 report_interval = FF_LAYOUTSTATS_REPORT_INTERVAL; s64 report_interval = FF_LAYOUTSTATS_REPORT_INTERVAL;
struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(mirror->layout);
nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now); nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now);
if (ktime_equal(mirror->start_time, notime)) if (ktime_equal(mirror->start_time, notime))
mirror->start_time = now; mirror->start_time = now;
if (ktime_equal(mirror->last_report_time, notime))
mirror->last_report_time = now;
if (mirror->report_interval != 0) if (mirror->report_interval != 0)
report_interval = (s64)mirror->report_interval * 1000LL; report_interval = (s64)mirror->report_interval * 1000LL;
else if (layoutstats_timer != 0) else if (layoutstats_timer != 0)
report_interval = (s64)layoutstats_timer * 1000LL; report_interval = (s64)layoutstats_timer * 1000LL;
if (ktime_to_ms(ktime_sub(now, mirror->last_report_time)) >= if (ktime_to_ms(ktime_sub(now, ffl->last_report_time)) >=
report_interval) { report_interval) {
mirror->last_report_time = now; ffl->last_report_time = now;
return true; return true;
} }
...@@ -806,11 +806,14 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg, ...@@ -806,11 +806,14 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
{ {
struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg);
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
bool fail_return = false;
int idx; int idx;
/* mirrors are sorted by efficiency */ /* mirrors are sorted by efficiency */
for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) {
ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); if (idx+1 == fls->mirror_array_cnt)
fail_return = true;
ds = nfs4_ff_layout_prepare_ds(lseg, idx, fail_return);
if (ds) { if (ds) {
*best_idx = idx; *best_idx = idx;
return ds; return ds;
...@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
int ds_idx; int ds_idx;
retry:
/* Use full layout for now */ /* Use full layout for now */
if (!pgio->pg_lseg) if (!pgio->pg_lseg)
ff_layout_pg_get_read(pgio, req, false); ff_layout_pg_get_read(pgio, req, false);
...@@ -871,10 +875,13 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -871,10 +875,13 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx);
if (!ds) { if (!ds) {
if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
goto out_pnfs;
else
goto out_mds; goto out_mds;
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
/* Sleep for 1 second before retrying */
ssleep(1);
goto retry;
} }
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
...@@ -890,12 +897,6 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -890,12 +897,6 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
pnfs_put_lseg(pgio->pg_lseg); pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
nfs_pageio_reset_read_mds(pgio); nfs_pageio_reset_read_mds(pgio);
return;
out_pnfs:
pnfs_set_lo_fail(pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
} }
static void static void
...@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
int i; int i;
int status; int status;
retry:
if (!pgio->pg_lseg) { if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context, req->wb_context,
...@@ -940,10 +942,13 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -940,10 +942,13 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
for (i = 0; i < pgio->pg_mirror_count; i++) { for (i = 0; i < pgio->pg_mirror_count; i++) {
ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true);
if (!ds) { if (!ds) {
if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
goto out_pnfs;
else
goto out_mds; goto out_mds;
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
/* Sleep for 1 second before retrying */
ssleep(1);
goto retry;
} }
pgm = &pgio->pg_mirrors[i]; pgm = &pgio->pg_mirrors[i];
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
...@@ -956,12 +961,6 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -956,12 +961,6 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
pnfs_put_lseg(pgio->pg_lseg); pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
nfs_pageio_reset_write_mds(pgio); nfs_pageio_reset_write_mds(pgio);
return;
out_pnfs:
pnfs_set_lo_fail(pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
} }
static unsigned int static unsigned int
......
...@@ -84,7 +84,6 @@ struct nfs4_ff_layout_mirror { ...@@ -84,7 +84,6 @@ struct nfs4_ff_layout_mirror {
struct nfs4_ff_layoutstat read_stat; struct nfs4_ff_layoutstat read_stat;
struct nfs4_ff_layoutstat write_stat; struct nfs4_ff_layoutstat write_stat;
ktime_t start_time; ktime_t start_time;
ktime_t last_report_time;
u32 report_interval; u32 report_interval;
}; };
...@@ -101,6 +100,7 @@ struct nfs4_flexfile_layout { ...@@ -101,6 +100,7 @@ struct nfs4_flexfile_layout {
struct pnfs_ds_commit_info commit_info; struct pnfs_ds_commit_info commit_info;
struct list_head mirrors; struct list_head mirrors;
struct list_head error_list; /* nfs4_ff_layout_ds_err */ struct list_head error_list; /* nfs4_ff_layout_ds_err */
ktime_t last_report_time; /* Layoutstat report times */
}; };
static inline struct nfs4_flexfile_layout * static inline struct nfs4_flexfile_layout *
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
#define NFSDBG_FACILITY NFSDBG_PNFS_LD #define NFSDBG_FACILITY NFSDBG_PNFS_LD
static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS;
static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; static unsigned int dataserver_retrans;
void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds) void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds)
{ {
...@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
devid = &mirror->mirror_ds->id_node; devid = &mirror->mirror_ds->id_node;
if (ff_layout_test_devid_unavailable(devid)) if (ff_layout_test_devid_unavailable(devid))
goto out; goto out_fail;
ds = mirror->mirror_ds->ds; ds = mirror->mirror_ds->ds;
/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
...@@ -405,15 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -405,15 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
mirror->mirror_ds->ds_versions[0].rsize = max_payload; mirror->mirror_ds->ds_versions[0].rsize = max_payload;
if (mirror->mirror_ds->ds_versions[0].wsize > max_payload) if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
mirror->mirror_ds->ds_versions[0].wsize = max_payload; mirror->mirror_ds->ds_versions[0].wsize = max_payload;
} else { goto out;
}
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, lseg->pls_range.offset, mirror, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO, lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO); OP_ILLEGAL, GFP_NOIO);
out_fail:
if (fail_return || !ff_layout_has_available_ds(lseg)) if (fail_return || !ff_layout_has_available_ds(lseg))
pnfs_error_mark_layout_for_return(ino, lseg); pnfs_error_mark_layout_for_return(ino, lseg);
ds = NULL; ds = NULL;
}
out: out:
return ds; return ds;
} }
......
...@@ -58,6 +58,9 @@ struct nfs_clone_mount { ...@@ -58,6 +58,9 @@ struct nfs_clone_mount {
*/ */
#define NFS_UNSPEC_PORT (-1) #define NFS_UNSPEC_PORT (-1)
#define NFS_UNSPEC_RETRANS (UINT_MAX)
#define NFS_UNSPEC_TIMEO (UINT_MAX)
/* /*
* Maximum number of pages that readdir can use for creating * Maximum number of pages that readdir can use for creating
* a vmapped array of pages. * a vmapped array of pages.
...@@ -156,7 +159,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *, ...@@ -156,7 +159,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *,
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *);
void nfs_server_insert_lists(struct nfs_server *); void nfs_server_insert_lists(struct nfs_server *);
void nfs_server_remove_lists(struct nfs_server *); void nfs_server_remove_lists(struct nfs_server *);
void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); void nfs_init_timeout_values(struct rpc_timeout *to, int proto, int timeo, int retrans);
int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t,
rpc_authflavor_t); rpc_authflavor_t);
struct nfs_server *nfs_alloc_server(void); struct nfs_server *nfs_alloc_server(void);
......
...@@ -318,10 +318,22 @@ static void ...@@ -318,10 +318,22 @@ static void
nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
{ {
struct nfs42_layoutstat_data *data = calldata; struct nfs42_layoutstat_data *data = calldata;
struct nfs_server *server = NFS_SERVER(data->args.inode); struct inode *inode = data->inode;
struct nfs_server *server = NFS_SERVER(inode);
struct pnfs_layout_hdr *lo;
spin_lock(&inode->i_lock);
lo = NFS_I(inode)->layout;
if (!pnfs_layout_is_valid(lo)) {
spin_unlock(&inode->i_lock);
rpc_exit(task, 0);
return;
}
nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
spin_unlock(&inode->i_lock);
nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args, nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args,
&data->res.seq_res, task); &data->res.seq_res, task);
} }
static void static void
...@@ -341,11 +353,11 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) ...@@ -341,11 +353,11 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
lo = NFS_I(inode)->layout; lo = NFS_I(inode)->layout;
if (lo && nfs4_stateid_match(&data->args.stateid, if (pnfs_layout_is_valid(lo) &&
nfs4_stateid_match(&data->args.stateid,
&lo->plh_stateid)) { &lo->plh_stateid)) {
LIST_HEAD(head); LIST_HEAD(head);
...@@ -359,11 +371,23 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) ...@@ -359,11 +371,23 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
} else } else
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
break; break;
case -NFS4ERR_OLD_STATEID:
spin_lock(&inode->i_lock);
lo = NFS_I(inode)->layout;
if (pnfs_layout_is_valid(lo) &&
nfs4_stateid_match_other(&data->args.stateid,
&lo->plh_stateid)) {
/* Do we need to delay before resending? */
if (!nfs4_stateid_is_newer(&lo->plh_stateid,
&data->args.stateid))
rpc_delay(task, HZ);
rpc_restart_call_prepare(task);
}
spin_unlock(&inode->i_lock);
break;
case -ENOTSUPP: case -ENOTSUPP:
case -EOPNOTSUPP: case -EOPNOTSUPP:
NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS; NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
default:
break;
} }
dprintk("%s server returns %d\n", __func__, task->tk_status); dprintk("%s server returns %d\n", __func__, task->tk_status);
......
...@@ -817,6 +817,11 @@ static int nfs4_set_client(struct nfs_server *server, ...@@ -817,6 +817,11 @@ static int nfs4_set_client(struct nfs_server *server,
goto error; goto error;
} }
if (server->nfs_client == clp) {
error = -ELOOP;
goto error;
}
/* /*
* Query for the lease time on clientid setup or renewal * Query for the lease time on clientid setup or renewal
* *
......
...@@ -634,15 +634,11 @@ int nfs40_setup_sequence(struct nfs4_slot_table *tbl, ...@@ -634,15 +634,11 @@ int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
} }
EXPORT_SYMBOL_GPL(nfs40_setup_sequence); EXPORT_SYMBOL_GPL(nfs40_setup_sequence);
static int nfs40_sequence_done(struct rpc_task *task, static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
struct nfs4_sequence_res *res)
{ {
struct nfs4_slot *slot = res->sr_slot; struct nfs4_slot *slot = res->sr_slot;
struct nfs4_slot_table *tbl; struct nfs4_slot_table *tbl;
if (slot == NULL)
goto out;
tbl = slot->table; tbl = slot->table;
spin_lock(&tbl->slot_tbl_lock); spin_lock(&tbl->slot_tbl_lock);
if (!nfs41_wake_and_assign_slot(tbl, slot)) if (!nfs41_wake_and_assign_slot(tbl, slot))
...@@ -650,7 +646,13 @@ static int nfs40_sequence_done(struct rpc_task *task, ...@@ -650,7 +646,13 @@ static int nfs40_sequence_done(struct rpc_task *task,
spin_unlock(&tbl->slot_tbl_lock); spin_unlock(&tbl->slot_tbl_lock);
res->sr_slot = NULL; res->sr_slot = NULL;
out: }
static int nfs40_sequence_done(struct rpc_task *task,
struct nfs4_sequence_res *res)
{
if (res->sr_slot != NULL)
nfs40_sequence_free_slot(res);
return 1; return 1;
} }
...@@ -666,6 +668,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) ...@@ -666,6 +668,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
tbl = slot->table; tbl = slot->table;
session = tbl->session; session = tbl->session;
/* Bump the slot sequence number */
if (slot->seq_done)
slot->seq_nr++;
slot->seq_done = 0;
spin_lock(&tbl->slot_tbl_lock); spin_lock(&tbl->slot_tbl_lock);
/* Be nice to the server: try to ensure that the last transmitted /* Be nice to the server: try to ensure that the last transmitted
* value for highest_user_slotid <= target_highest_slotid * value for highest_user_slotid <= target_highest_slotid
...@@ -686,9 +693,12 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) ...@@ -686,9 +693,12 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
res->sr_slot = NULL; res->sr_slot = NULL;
if (send_new_highest_used_slotid) if (send_new_highest_used_slotid)
nfs41_notify_server(session->clp); nfs41_notify_server(session->clp);
if (waitqueue_active(&tbl->slot_waitq))
wake_up_all(&tbl->slot_waitq);
} }
int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) static int nfs41_sequence_process(struct rpc_task *task,
struct nfs4_sequence_res *res)
{ {
struct nfs4_session *session; struct nfs4_session *session;
struct nfs4_slot *slot = res->sr_slot; struct nfs4_slot *slot = res->sr_slot;
...@@ -714,7 +724,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) ...@@ -714,7 +724,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
switch (res->sr_status) { switch (res->sr_status) {
case 0: case 0:
/* Update the slot's sequence and clientid lease timer */ /* Update the slot's sequence and clientid lease timer */
++slot->seq_nr; slot->seq_done = 1;
clp = session->clp; clp = session->clp;
do_renew_lease(clp, res->sr_timestamp); do_renew_lease(clp, res->sr_timestamp);
/* Check sequence flags */ /* Check sequence flags */
...@@ -769,16 +779,16 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) ...@@ -769,16 +779,16 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
goto retry_nowait; goto retry_nowait;
default: default:
/* Just update the slot sequence no. */ /* Just update the slot sequence no. */
++slot->seq_nr; slot->seq_done = 1;
} }
out: out:
/* The session may be reset by one of the error handlers. */ /* The session may be reset by one of the error handlers. */
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
nfs41_sequence_free_slot(res);
out_noaction: out_noaction:
return ret; return ret;
retry_nowait: retry_nowait:
if (rpc_restart_call_prepare(task)) { if (rpc_restart_call_prepare(task)) {
nfs41_sequence_free_slot(res);
task->tk_status = 0; task->tk_status = 0;
ret = 0; ret = 0;
} }
...@@ -789,8 +799,37 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) ...@@ -789,8 +799,37 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
rpc_delay(task, NFS4_POLL_RETRY_MAX); rpc_delay(task, NFS4_POLL_RETRY_MAX);
return 0; return 0;
} }
int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{
if (!nfs41_sequence_process(task, res))
return 0;
if (res->sr_slot != NULL)
nfs41_sequence_free_slot(res);
return 1;
}
EXPORT_SYMBOL_GPL(nfs41_sequence_done); EXPORT_SYMBOL_GPL(nfs41_sequence_done);
static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
{
if (res->sr_slot == NULL)
return 1;
if (res->sr_slot->table->session != NULL)
return nfs41_sequence_process(task, res);
return nfs40_sequence_done(task, res);
}
static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
{
if (res->sr_slot != NULL) {
if (res->sr_slot->table->session != NULL)
nfs41_sequence_free_slot(res);
else
nfs40_sequence_free_slot(res);
}
}
int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{ {
if (res->sr_slot == NULL) if (res->sr_slot == NULL)
...@@ -920,6 +959,17 @@ static int nfs4_setup_sequence(const struct nfs_server *server, ...@@ -920,6 +959,17 @@ static int nfs4_setup_sequence(const struct nfs_server *server,
args, res, task); args, res, task);
} }
static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
{
return nfs40_sequence_done(task, res);
}
static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
{
if (res->sr_slot != NULL)
nfs40_sequence_free_slot(res);
}
int nfs4_sequence_done(struct rpc_task *task, int nfs4_sequence_done(struct rpc_task *task,
struct nfs4_sequence_res *res) struct nfs4_sequence_res *res)
{ {
...@@ -1197,6 +1247,7 @@ static void nfs4_opendata_free(struct kref *kref) ...@@ -1197,6 +1247,7 @@ static void nfs4_opendata_free(struct kref *kref)
struct super_block *sb = p->dentry->d_sb; struct super_block *sb = p->dentry->d_sb;
nfs_free_seqid(p->o_arg.seqid); nfs_free_seqid(p->o_arg.seqid);
nfs4_sequence_free_slot(&p->o_res.seq_res);
if (p->state != NULL) if (p->state != NULL)
nfs4_put_open_state(p->state); nfs4_put_open_state(p->state);
nfs4_put_state_owner(p->owner); nfs4_put_state_owner(p->owner);
...@@ -1656,9 +1707,14 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) ...@@ -1656,9 +1707,14 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
static struct nfs4_state * static struct nfs4_state *
nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{ {
struct nfs4_state *ret;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
return _nfs4_opendata_reclaim_to_nfs4_state(data); ret =_nfs4_opendata_reclaim_to_nfs4_state(data);
return _nfs4_opendata_to_nfs4_state(data); else
ret = _nfs4_opendata_to_nfs4_state(data);
nfs4_sequence_free_slot(&data->o_res.seq_res);
return ret;
} }
static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
...@@ -2056,7 +2112,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) ...@@ -2056,7 +2112,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
data->rpc_status = task->tk_status; data->rpc_status = task->tk_status;
if (!nfs4_sequence_done(task, &data->o_res.seq_res)) if (!nfs4_sequence_process(task, &data->o_res.seq_res))
return; return;
if (task->tk_status == 0) { if (task->tk_status == 0) {
...@@ -7864,7 +7920,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) ...@@ -7864,7 +7920,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
struct nfs4_layoutget *lgp = calldata; struct nfs4_layoutget *lgp = calldata;
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
nfs41_sequence_done(task, &lgp->res.seq_res); nfs41_sequence_process(task, &lgp->res.seq_res);
dprintk("<-- %s\n", __func__); dprintk("<-- %s\n", __func__);
} }
...@@ -8080,6 +8136,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags) ...@@ -8080,6 +8136,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
/* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
if (status == 0 && lgp->res.layoutp->len) if (status == 0 && lgp->res.layoutp->len)
lseg = pnfs_layout_process(lgp); lseg = pnfs_layout_process(lgp);
nfs4_sequence_free_slot(&lgp->res.seq_res);
rpc_put_task(task); rpc_put_task(task);
dprintk("<-- %s status=%d\n", __func__, status); dprintk("<-- %s status=%d\n", __func__, status);
if (status) if (status)
...@@ -8106,7 +8163,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) ...@@ -8106,7 +8163,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
if (!nfs41_sequence_done(task, &lrp->res.seq_res)) if (!nfs41_sequence_process(task, &lrp->res.seq_res))
return; return;
server = NFS_SERVER(lrp->args.inode); server = NFS_SERVER(lrp->args.inode);
...@@ -8118,6 +8175,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) ...@@ -8118,6 +8175,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_DELAY: case -NFS4ERR_DELAY:
if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN) if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
break; break;
nfs4_sequence_free_slot(&lrp->res.seq_res);
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
return; return;
} }
...@@ -8138,6 +8196,7 @@ static void nfs4_layoutreturn_release(void *calldata) ...@@ -8138,6 +8196,7 @@ static void nfs4_layoutreturn_release(void *calldata)
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
pnfs_clear_layoutreturn_waitbit(lo); pnfs_clear_layoutreturn_waitbit(lo);
spin_unlock(&lo->plh_inode->i_lock); spin_unlock(&lo->plh_inode->i_lock);
nfs4_sequence_free_slot(&lrp->res.seq_res);
pnfs_free_lseg_list(&freeme); pnfs_free_lseg_list(&freeme);
pnfs_put_layout_hdr(lrp->args.layout); pnfs_put_layout_hdr(lrp->args.layout);
nfs_iput_and_deactive(lrp->inode); nfs_iput_and_deactive(lrp->inode);
......
...@@ -28,6 +28,7 @@ static void nfs4_init_slot_table(struct nfs4_slot_table *tbl, const char *queue) ...@@ -28,6 +28,7 @@ static void nfs4_init_slot_table(struct nfs4_slot_table *tbl, const char *queue)
tbl->highest_used_slotid = NFS4_NO_SLOT; tbl->highest_used_slotid = NFS4_NO_SLOT;
spin_lock_init(&tbl->slot_tbl_lock); spin_lock_init(&tbl->slot_tbl_lock);
rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, queue); rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, queue);
init_waitqueue_head(&tbl->slot_waitq);
init_completion(&tbl->complete); init_completion(&tbl->complete);
} }
...@@ -172,6 +173,58 @@ struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid) ...@@ -172,6 +173,58 @@ struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid)
return ERR_PTR(-E2BIG); return ERR_PTR(-E2BIG);
} }
static int nfs4_slot_get_seqid(struct nfs4_slot_table *tbl, u32 slotid,
u32 *seq_nr)
__must_hold(&tbl->slot_tbl_lock)
{
struct nfs4_slot *slot;
slot = nfs4_lookup_slot(tbl, slotid);
if (IS_ERR(slot))
return PTR_ERR(slot);
*seq_nr = slot->seq_nr;
return 0;
}
/*
* nfs4_slot_seqid_in_use - test if a slot sequence id is still in use
*
* Given a slot table, slot id and sequence number, determine if the
* RPC call in question is still in flight. This function is mainly
* intended for use by the callback channel.
*/
static bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl,
u32 slotid, u32 seq_nr)
{
u32 cur_seq;
bool ret = false;
spin_lock(&tbl->slot_tbl_lock);
if (nfs4_slot_get_seqid(tbl, slotid, &cur_seq) == 0 &&
cur_seq == seq_nr && test_bit(slotid, tbl->used_slots))
ret = true;
spin_unlock(&tbl->slot_tbl_lock);
return ret;
}
/*
* nfs4_slot_wait_on_seqid - wait until a slot sequence id is complete
*
* Given a slot table, slot id and sequence number, wait until the
* corresponding RPC call completes. This function is mainly
* intended for use by the callback channel.
*/
int nfs4_slot_wait_on_seqid(struct nfs4_slot_table *tbl,
u32 slotid, u32 seq_nr,
unsigned long timeout)
{
if (wait_event_timeout(tbl->slot_waitq,
!nfs4_slot_seqid_in_use(tbl, slotid, seq_nr),
timeout) == 0)
return -ETIMEDOUT;
return 0;
}
/* /*
* nfs4_alloc_slot - efficiently look for a free slot * nfs4_alloc_slot - efficiently look for a free slot
* *
......
...@@ -21,7 +21,8 @@ struct nfs4_slot { ...@@ -21,7 +21,8 @@ struct nfs4_slot {
unsigned long generation; unsigned long generation;
u32 slot_nr; u32 slot_nr;
u32 seq_nr; u32 seq_nr;
unsigned int interrupted : 1; unsigned int interrupted : 1,
seq_done : 1;
}; };
/* Sessions */ /* Sessions */
...@@ -36,6 +37,7 @@ struct nfs4_slot_table { ...@@ -36,6 +37,7 @@ struct nfs4_slot_table {
unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
spinlock_t slot_tbl_lock; spinlock_t slot_tbl_lock;
struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */
wait_queue_head_t slot_waitq; /* Completion wait on slot */
u32 max_slots; /* # slots in table */ u32 max_slots; /* # slots in table */
u32 max_slotid; /* Max allowed slotid value */ u32 max_slotid; /* Max allowed slotid value */
u32 highest_used_slotid; /* sent to server on each SEQ. u32 highest_used_slotid; /* sent to server on each SEQ.
...@@ -78,6 +80,9 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, ...@@ -78,6 +80,9 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid);
extern int nfs4_slot_wait_on_seqid(struct nfs4_slot_table *tbl,
u32 slotid, u32 seq_nr,
unsigned long timeout);
extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);
......
...@@ -1555,6 +1555,7 @@ pnfs_update_layout(struct inode *ino, ...@@ -1555,6 +1555,7 @@ pnfs_update_layout(struct inode *ino,
} }
lookup_again: lookup_again:
nfs4_client_recover_expired_lease(clp);
first = false; first = false;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags); lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
...@@ -2510,7 +2511,6 @@ pnfs_report_layoutstat(struct inode *inode, gfp_t gfp_flags) ...@@ -2510,7 +2511,6 @@ pnfs_report_layoutstat(struct inode *inode, gfp_t gfp_flags)
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.inode = inode; data->args.inode = inode;
nfs4_stateid_copy(&data->args.stateid, &hdr->plh_stateid);
status = ld->prepare_layoutstats(&data->args); status = ld->prepare_layoutstats(&data->args);
if (status) if (status)
goto out_free; goto out_free;
......
...@@ -923,6 +923,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) ...@@ -923,6 +923,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data) { if (data) {
data->timeo = NFS_UNSPEC_TIMEO;
data->retrans = NFS_UNSPEC_RETRANS;
data->acregmin = NFS_DEF_ACREGMIN; data->acregmin = NFS_DEF_ACREGMIN;
data->acregmax = NFS_DEF_ACREGMAX; data->acregmax = NFS_DEF_ACREGMAX;
data->acdirmin = NFS_DEF_ACDIRMIN; data->acdirmin = NFS_DEF_ACDIRMIN;
...@@ -1189,6 +1191,19 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option) ...@@ -1189,6 +1191,19 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option)
return rc; return rc;
} }
static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
unsigned long l_bound, unsigned long u_bound)
{
int ret;
ret = nfs_get_option_ul(args, option);
if (ret != 0)
return ret;
if (*option < l_bound || *option > u_bound)
return -ERANGE;
return 0;
}
/* /*
* Error-check and convert a string of mount options from user space into * Error-check and convert a string of mount options from user space into
* a data structure. The whole mount string is processed; bad options are * a data structure. The whole mount string is processed; bad options are
...@@ -1352,12 +1367,12 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1352,12 +1367,12 @@ static int nfs_parse_mount_options(char *raw,
mnt->bsize = option; mnt->bsize = option;
break; break;
case Opt_timeo: case Opt_timeo:
if (nfs_get_option_ul(args, &option) || option == 0) if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
goto out_invalid_value; goto out_invalid_value;
mnt->timeo = option; mnt->timeo = option;
break; break;
case Opt_retrans: case Opt_retrans:
if (nfs_get_option_ul(args, &option) || option == 0) if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
goto out_invalid_value; goto out_invalid_value;
mnt->retrans = option; mnt->retrans = option;
break; break;
......
...@@ -453,7 +453,7 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args, ...@@ -453,7 +453,7 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
struct rpc_xprt_switch *xps; struct rpc_xprt_switch *xps;
if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) { if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) {
WARN_ON(args->protocol != XPRT_TRANSPORT_BC_TCP); WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
xps = args->bc_xprt->xpt_bc_xps; xps = args->bc_xprt->xpt_bc_xps;
xprt_switch_get(xps); xprt_switch_get(xps);
} else { } else {
...@@ -520,7 +520,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) ...@@ -520,7 +520,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
char servername[48]; char servername[48];
if (args->bc_xprt) { if (args->bc_xprt) {
WARN_ON(args->protocol != XPRT_TRANSPORT_BC_TCP); WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
xprt = args->bc_xprt->xpt_bc_xprt; xprt = args->bc_xprt->xpt_bc_xprt;
if (xprt) { if (xprt) {
xprt_get(xprt); xprt_get(xprt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment