Commit 2b3a8fd7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

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

   - Stable fix for a use after free issue in the NFSv4.1 open code
   - Fix the SUNRPC bi-directional RPC code to account for TCP segmentation
   - Optimise usage of readdirplus when confronted with 'ls -l' situations
   - Soft mount bugfixes
   - NFS over RDMA bugfixes
   - NFSv4 close locking fixes
   - Various NFSv4.x client state management optimisations
   - Rename/unlink code cleanups"

* tag 'nfs-for-3.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (28 commits)
  nfs: pass string length to pr_notice message about readdir loops
  NFSv4: Fix a use-after-free problem in open()
  SUNRPC: rpc_restart_call/rpc_restart_call_prepare should clear task->tk_status
  SUNRPC: Don't let rpc_delay() clobber non-timeout errors
  SUNRPC: Ensure call_connect_status() deals correctly with SOFTCONN tasks
  SUNRPC: Ensure call_status() deals correctly with SOFTCONN tasks
  NFSv4: Ensure we respect soft mount timeouts during trunking discovery
  NFSv4: Schedule recovery if nfs40_walk_client_list() is interrupted
  NFS: advertise only supported callback netids
  SUNRPC: remove KERN_INFO from dprintk() call sites
  SUNRPC: Fix large reads on NFS/RDMA
  NFS: Clean up: revert increase in READDIR RPC buffer max size
  SUNRPC: Ensure that call_bind times out correctly
  SUNRPC: Ensure that call_connect times out correctly
  nfs: emit a fsnotify_nameremove call in sillyrename codepath
  nfs: remove synchronous rename code
  nfs: convert nfs_rename to use async_rename infrastructure
  nfs: make nfs_async_rename non-static
  nfs: abstract out code needed to complete a sillyrename
  NFSv4: Clear the open state flags if the new stateid does not match
  ...
parents 6f4c98e1 9581a4ae
...@@ -112,7 +112,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, ...@@ -112,7 +112,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
* TODO: keep track of all layouts (and delegations) in a hash table * TODO: keep track of all layouts (and delegations) in a hash table
* hashed by filehandle. * hashed by filehandle.
*/ */
static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh) static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
struct nfs_fh *fh, nfs4_stateid *stateid)
{ {
struct nfs_server *server; struct nfs_server *server;
struct inode *ino; struct inode *ino;
...@@ -120,17 +121,19 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, ...@@ -120,17 +121,19 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
list_for_each_entry(lo, &server->layouts, plh_layouts) { list_for_each_entry(lo, &server->layouts, plh_layouts) {
if (!nfs4_stateid_match_other(&lo->plh_stateid, stateid))
continue;
if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
continue; continue;
ino = igrab(lo->plh_inode); ino = igrab(lo->plh_inode);
if (!ino) if (!ino)
continue; break;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
/* Is this layout in the process of being freed? */ /* Is this layout in the process of being freed? */
if (NFS_I(ino)->layout != lo) { if (NFS_I(ino)->layout != lo) {
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
iput(ino); iput(ino);
continue; break;
} }
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
...@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, ...@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
return NULL; return NULL;
} }
static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
struct nfs_fh *fh, nfs4_stateid *stateid)
{ {
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
rcu_read_lock(); rcu_read_lock();
lo = get_layout_by_fh_locked(clp, fh); lo = get_layout_by_fh_locked(clp, fh, stateid);
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
...@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp,
u32 rv = NFS4ERR_NOMATCHING_LAYOUT; u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
LIST_HEAD(free_me_list); LIST_HEAD(free_me_list);
lo = get_layout_by_fh(clp, &args->cbl_fh); lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid);
if (!lo) if (!lo)
return NFS4ERR_NOMATCHING_LAYOUT; goto out;
ino = lo->plh_inode; ino = lo->plh_inode;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
...@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
pnfs_free_lseg_list(&free_me_list); pnfs_free_lseg_list(&free_me_list);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
iput(ino); iput(ino);
out:
return rv; return rv;
} }
......
...@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = { ...@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = {
static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
{ {
struct nfs_inode *nfsi = NFS_I(dir);
struct nfs_open_dir_context *ctx; struct nfs_open_dir_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) { if (ctx != NULL) {
ctx->duped = 0; ctx->duped = 0;
ctx->attr_gencount = NFS_I(dir)->attr_gencount; ctx->attr_gencount = nfsi->attr_gencount;
ctx->dir_cookie = 0; ctx->dir_cookie = 0;
ctx->dup_cookie = 0; ctx->dup_cookie = 0;
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
spin_lock(&dir->i_lock);
list_add(&ctx->list, &nfsi->open_files);
spin_unlock(&dir->i_lock);
return ctx; return ctx;
} }
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx)
{ {
spin_lock(&dir->i_lock);
list_del(&ctx->list);
spin_unlock(&dir->i_lock);
put_rpccred(ctx->cred); put_rpccred(ctx->cred);
kfree(ctx); kfree(ctx);
} }
...@@ -126,7 +133,7 @@ nfs_opendir(struct inode *inode, struct file *filp) ...@@ -126,7 +133,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
static int static int
nfs_closedir(struct inode *inode, struct file *filp) nfs_closedir(struct inode *inode, struct file *filp)
{ {
put_nfs_open_dir_context(filp->private_data); put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data);
return 0; return 0;
} }
...@@ -306,10 +313,9 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des ...@@ -306,10 +313,9 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
if (printk_ratelimit()) { if (printk_ratelimit()) {
pr_notice("NFS: directory %pD2 contains a readdir loop." pr_notice("NFS: directory %pD2 contains a readdir loop."
"Please contact your server vendor. " "Please contact your server vendor. "
"The file: %s has duplicate cookie %llu\n", "The file: %.*s has duplicate cookie %llu\n",
desc->file, desc->file, array->array[i].string.len,
array->array[i].string.name, array->array[i].string.name, *desc->dir_cookie);
*desc->dir_cookie);
} }
status = -ELOOP; status = -ELOOP;
goto out; goto out;
...@@ -437,6 +443,22 @@ void nfs_advise_use_readdirplus(struct inode *dir) ...@@ -437,6 +443,22 @@ void nfs_advise_use_readdirplus(struct inode *dir)
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags);
} }
/*
* This function is mainly for use by nfs_getattr().
*
* If this is an 'ls -l', we want to force use of readdirplus.
* Do this by checking if there is an active file descriptor
* and calling nfs_advise_use_readdirplus, then forcing a
* cache flush.
*/
void nfs_force_use_readdirplus(struct inode *dir)
{
if (!list_empty(&NFS_I(dir)->open_files)) {
nfs_advise_use_readdirplus(dir);
nfs_zap_mapping(dir, dir->i_mapping);
}
}
static static
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
{ {
...@@ -815,6 +837,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc) ...@@ -815,6 +837,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
goto out; goto out;
} }
static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
{
struct nfs_inode *nfsi = NFS_I(dir);
if (nfs_attribute_cache_expired(dir))
return true;
if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
return true;
return false;
}
/* The file offset position represents the dirent entry number. A /* The file offset position represents the dirent entry number. A
last cookie cache takes care of the common case of reading the last cookie cache takes care of the common case of reading the
whole directory. whole directory.
...@@ -847,7 +880,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -847,7 +880,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
nfs_block_sillyrename(dentry); nfs_block_sillyrename(dentry);
if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
res = nfs_revalidate_mapping(inode, file->f_mapping); res = nfs_revalidate_mapping(inode, file->f_mapping);
if (res < 0) if (res < 0)
goto out; goto out;
...@@ -1911,6 +1944,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1911,6 +1944,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode = old_dentry->d_inode; struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode;
struct dentry *dentry = NULL, *rehash = NULL; struct dentry *dentry = NULL, *rehash = NULL;
struct rpc_task *task;
int error = -EBUSY; int error = -EBUSY;
dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n",
...@@ -1958,8 +1992,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1958,8 +1992,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode != NULL) if (new_inode != NULL)
NFS_PROTO(new_inode)->return_delegation(new_inode); NFS_PROTO(new_inode)->return_delegation(new_inode);
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
new_dir, &new_dentry->d_name); if (IS_ERR(task)) {
error = PTR_ERR(task);
goto out;
}
error = rpc_wait_for_completion_task(task);
if (error == 0)
error = task->tk_status;
rpc_put_task(task);
nfs_mark_for_revalidate(old_inode); nfs_mark_for_revalidate(old_inode);
out: out:
if (rehash) if (rehash)
......
...@@ -588,6 +588,25 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) ...@@ -588,6 +588,25 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
} }
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
static void nfs_request_parent_use_readdirplus(struct dentry *dentry)
{
struct dentry *parent;
parent = dget_parent(dentry);
nfs_force_use_readdirplus(parent->d_inode);
dput(parent);
}
static bool nfs_need_revalidate_inode(struct inode *inode)
{
if (NFS_I(inode)->cache_validity &
(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
return true;
if (nfs_attribute_cache_expired(inode))
return true;
return false;
}
int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
...@@ -616,10 +635,13 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -616,10 +635,13 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
need_atime = 0; need_atime = 0;
if (need_atime) if (need_atime || nfs_need_revalidate_inode(inode)) {
err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); struct nfs_server *server = NFS_SERVER(inode);
else
err = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (server->caps & NFS_CAP_READDIRPLUS)
nfs_request_parent_use_readdirplus(dentry);
err = __nfs_revalidate_inode(server, inode);
}
if (!err) { if (!err) {
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
...@@ -961,9 +983,7 @@ int nfs_attribute_cache_expired(struct inode *inode) ...@@ -961,9 +983,7 @@ int nfs_attribute_cache_expired(struct inode *inode)
*/ */
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{ {
if (!(NFS_I(inode)->cache_validity & if (!nfs_need_revalidate_inode(inode))
(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
&& !nfs_attribute_cache_expired(inode))
return NFS_STALE(inode) ? -ESTALE : 0; return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode); return __nfs_revalidate_inode(server, inode);
} }
......
...@@ -301,6 +301,7 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp, ...@@ -301,6 +301,7 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
const char *ip_addr); const char *ip_addr);
/* dir.c */ /* dir.c */
extern void nfs_force_use_readdirplus(struct inode *dir);
extern unsigned long nfs_access_cache_count(struct shrinker *shrink, extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
struct shrink_control *sc); struct shrink_control *sc);
extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
...@@ -474,6 +475,13 @@ extern int nfs_migrate_page(struct address_space *, ...@@ -474,6 +475,13 @@ extern int nfs_migrate_page(struct address_space *,
#define nfs_migrate_page NULL #define nfs_migrate_page NULL
#endif #endif
/* unlink.c */
extern struct rpc_task *
nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
struct dentry *old_dentry, struct dentry *new_dentry,
void (*complete)(struct rpc_task *, struct nfs_renamedata *));
extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);
/* direct.c */ /* direct.c */
void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
struct nfs_direct_req *dreq); struct nfs_direct_req *dreq);
......
...@@ -478,41 +478,6 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, ...@@ -478,41 +478,6 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
return 1; return 1;
} }
static int
nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
struct nfs_renameargs arg = {
.old_dir = NFS_FH(old_dir),
.old_name = old_name,
.new_dir = NFS_FH(new_dir),
.new_name = new_name,
};
struct nfs_renameres res;
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_RENAME],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status = -ENOMEM;
dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
res.old_fattr = nfs_alloc_fattr();
res.new_fattr = nfs_alloc_fattr();
if (res.old_fattr == NULL || res.new_fattr == NULL)
goto out;
status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
nfs_post_op_update_inode(old_dir, res.old_fattr);
nfs_post_op_update_inode(new_dir, res.new_fattr);
out:
nfs_free_fattr(res.old_fattr);
nfs_free_fattr(res.new_fattr);
dprintk("NFS reply rename: %d\n", status);
return status;
}
static int static int
nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{ {
...@@ -968,7 +933,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -968,7 +933,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.unlink_setup = nfs3_proc_unlink_setup, .unlink_setup = nfs3_proc_unlink_setup,
.unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
.unlink_done = nfs3_proc_unlink_done, .unlink_done = nfs3_proc_unlink_done,
.rename = nfs3_proc_rename,
.rename_setup = nfs3_proc_rename_setup, .rename_setup = nfs3_proc_rename_setup,
.rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
.rename_done = nfs3_proc_rename_done, .rename_done = nfs3_proc_rename_done,
......
...@@ -427,6 +427,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t); ...@@ -427,6 +427,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
extern void nfs_inode_find_state_and_recover(struct inode *inode, extern void nfs_inode_find_state_and_recover(struct inode *inode,
const nfs4_stateid *stateid); const nfs4_stateid *stateid);
extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *, struct nfs4_state *);
extern void nfs4_schedule_lease_recovery(struct nfs_client *); extern void nfs4_schedule_lease_recovery(struct nfs_client *);
extern int nfs4_wait_clnt_recover(struct nfs_client *clp); extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
...@@ -500,6 +501,16 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei ...@@ -500,6 +501,16 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei
return memcmp(dst, src, sizeof(*dst)) == 0; return memcmp(dst, src, sizeof(*dst)) == 0;
} }
static inline bool nfs4_stateid_match_other(const nfs4_stateid *dst, const nfs4_stateid *src)
{
return memcmp(dst->other, src->other, NFS4_STATEID_OTHER_SIZE) == 0;
}
static inline bool nfs4_stateid_is_newer(const nfs4_stateid *s1, const nfs4_stateid *s2)
{
return (s32)(be32_to_cpu(s1->seqid) - be32_to_cpu(s2->seqid)) > 0;
}
static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
{ {
return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
......
...@@ -531,6 +531,13 @@ int nfs40_walk_client_list(struct nfs_client *new, ...@@ -531,6 +531,13 @@ int nfs40_walk_client_list(struct nfs_client *new,
*result = pos; *result = pos;
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
__func__, pos, atomic_read(&pos->cl_count)); __func__, pos, atomic_read(&pos->cl_count));
goto out;
case -ERESTARTSYS:
case -ETIMEDOUT:
/* The callback path may have been inadvertently
* changed. Schedule recovery!
*/
nfs4_schedule_path_down_recovery(pos);
default: default:
goto out; goto out;
} }
......
This diff is collapsed.
...@@ -1316,7 +1316,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st ...@@ -1316,7 +1316,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st
return 1; return 1;
} }
static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
{ {
set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
...@@ -2075,8 +2075,10 @@ int nfs4_discover_server_trunking(struct nfs_client *clp, ...@@ -2075,8 +2075,10 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
switch (status) { switch (status) {
case 0: case 0:
break; break;
case -NFS4ERR_DELAY:
case -ETIMEDOUT: case -ETIMEDOUT:
if (clnt->cl_softrtry)
break;
case -NFS4ERR_DELAY:
case -EAGAIN: case -EAGAIN:
ssleep(1); ssleep(1);
case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_CLIENTID:
......
...@@ -203,8 +203,7 @@ static int nfs4_stat_to_errno(int); ...@@ -203,8 +203,7 @@ static int nfs4_stat_to_errno(int);
2 + encode_verifier_maxsz + 5 + \ 2 + encode_verifier_maxsz + 5 + \
nfs4_label_maxsz) nfs4_label_maxsz)
#define decode_readdir_maxsz (op_decode_hdr_maxsz + \ #define decode_readdir_maxsz (op_decode_hdr_maxsz + \
decode_verifier_maxsz + \ decode_verifier_maxsz)
nfs4_label_maxsz + nfs4_fattr_maxsz)
#define encode_readlink_maxsz (op_encode_hdr_maxsz) #define encode_readlink_maxsz (op_encode_hdr_maxsz)
#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1)
#define encode_write_maxsz (op_encode_hdr_maxsz + \ #define encode_write_maxsz (op_encode_hdr_maxsz + \
......
...@@ -662,7 +662,18 @@ pnfs_destroy_all_layouts(struct nfs_client *clp) ...@@ -662,7 +662,18 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
*/ */
static bool pnfs_seqid_is_newer(u32 s1, u32 s2) static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
{ {
return (s32)s1 - (s32)s2 > 0; return (s32)(s1 - s2) > 0;
}
static void
pnfs_verify_layout_stateid(struct pnfs_layout_hdr *lo,
const nfs4_stateid *new,
struct list_head *free_me_list)
{
if (nfs4_stateid_match_other(&lo->plh_stateid, new))
return;
/* Layout is new! Kill existing layout segments */
pnfs_mark_matching_lsegs_invalid(lo, free_me_list, NULL);
} }
/* update lo->plh_stateid with new if is more recent */ /* update lo->plh_stateid with new if is more recent */
...@@ -1315,6 +1326,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) ...@@ -1315,6 +1326,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
struct nfs4_layoutget_res *res = &lgp->res; struct nfs4_layoutget_res *res = &lgp->res;
struct pnfs_layout_segment *lseg; struct pnfs_layout_segment *lseg;
struct inode *ino = lo->plh_inode; struct inode *ino = lo->plh_inode;
LIST_HEAD(free_me);
int status = 0; int status = 0;
/* Inject layout blob into I/O device driver */ /* Inject layout blob into I/O device driver */
...@@ -1341,6 +1353,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) ...@@ -1341,6 +1353,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
goto out_forget_reply; goto out_forget_reply;
} }
/* Check that the new stateid matches the old stateid */
pnfs_verify_layout_stateid(lo, &res->stateid, &free_me);
/* Done processing layoutget. Set the layout stateid */ /* Done processing layoutget. Set the layout stateid */
pnfs_set_layout_stateid(lo, &res->stateid, false); pnfs_set_layout_stateid(lo, &res->stateid, false);
...@@ -1355,6 +1369,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) ...@@ -1355,6 +1369,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
} }
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&free_me);
return lseg; return lseg;
out: out:
return ERR_PTR(status); return ERR_PTR(status);
......
...@@ -356,30 +356,6 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, ...@@ -356,30 +356,6 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
return 1; return 1;
} }
static int
nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
struct nfs_renameargs arg = {
.old_dir = NFS_FH(old_dir),
.old_name = old_name,
.new_dir = NFS_FH(new_dir),
.new_name = new_name,
};
struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_RENAME],
.rpc_argp = &arg,
};
int status;
dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
nfs_mark_for_revalidate(old_dir);
nfs_mark_for_revalidate(new_dir);
dprintk("NFS reply rename: %d\n", status);
return status;
}
static int static int
nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{ {
...@@ -745,7 +721,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -745,7 +721,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.unlink_setup = nfs_proc_unlink_setup, .unlink_setup = nfs_proc_unlink_setup,
.unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare, .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare,
.unlink_done = nfs_proc_unlink_done, .unlink_done = nfs_proc_unlink_done,
.rename = nfs_proc_rename,
.rename_setup = nfs_proc_rename_setup, .rename_setup = nfs_proc_rename_setup,
.rename_rpc_prepare = nfs_proc_rename_rpc_prepare, .rename_rpc_prepare = nfs_proc_rename_rpc_prepare,
.rename_done = nfs_proc_rename_done, .rename_done = nfs_proc_rename_done,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/fsnotify.h>
#include "internal.h" #include "internal.h"
#include "nfs4_fs.h" #include "nfs4_fs.h"
...@@ -353,8 +354,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) ...@@ -353,8 +354,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
return; return;
} }
if (task->tk_status != 0) if (data->complete)
nfs_cancel_async_unlink(old_dentry); data->complete(task, data);
} }
/** /**
...@@ -399,9 +400,10 @@ static const struct rpc_call_ops nfs_rename_ops = { ...@@ -399,9 +400,10 @@ static const struct rpc_call_ops nfs_rename_ops = {
* *
* It's expected that valid references to the dentries and inodes are held * It's expected that valid references to the dentries and inodes are held
*/ */
static struct rpc_task * struct rpc_task *
nfs_async_rename(struct inode *old_dir, struct inode *new_dir, nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
struct dentry *old_dentry, struct dentry *new_dentry) struct dentry *old_dentry, struct dentry *new_dentry,
void (*complete)(struct rpc_task *, struct nfs_renamedata *))
{ {
struct nfs_renamedata *data; struct nfs_renamedata *data;
struct rpc_message msg = { }; struct rpc_message msg = { };
...@@ -438,6 +440,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, ...@@ -438,6 +440,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
data->new_dentry = dget(new_dentry); data->new_dentry = dget(new_dentry);
nfs_fattr_init(&data->old_fattr); nfs_fattr_init(&data->old_fattr);
nfs_fattr_init(&data->new_fattr); nfs_fattr_init(&data->new_fattr);
data->complete = complete;
/* set up nfs_renameargs */ /* set up nfs_renameargs */
data->args.old_dir = NFS_FH(old_dir); data->args.old_dir = NFS_FH(old_dir);
...@@ -456,6 +459,27 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, ...@@ -456,6 +459,27 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
return rpc_run_task(&task_setup_data); return rpc_run_task(&task_setup_data);
} }
/*
* Perform tasks needed when a sillyrename is done such as cancelling the
* queued async unlink if it failed.
*/
static void
nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data)
{
struct dentry *dentry = data->old_dentry;
if (task->tk_status != 0) {
nfs_cancel_async_unlink(dentry);
return;
}
/*
* vfs_unlink and the like do not issue this when a file is
* sillyrenamed, so do it here.
*/
fsnotify_nameremove(dentry, 0);
}
#define SILLYNAME_PREFIX ".nfs" #define SILLYNAME_PREFIX ".nfs"
#define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1) #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1)
#define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1) #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1)
...@@ -548,7 +572,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) ...@@ -548,7 +572,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
} }
/* run the rename task, undo unlink if it fails */ /* run the rename task, undo unlink if it fails */
task = nfs_async_rename(dir, dir, dentry, sdentry); task = nfs_async_rename(dir, dir, dentry, sdentry,
nfs_complete_sillyrename);
if (IS_ERR(task)) { if (IS_ERR(task)) {
error = -EBUSY; error = -EBUSY;
nfs_cancel_async_unlink(dentry); nfs_cancel_async_unlink(dentry);
......
...@@ -92,6 +92,7 @@ struct nfs_open_context { ...@@ -92,6 +92,7 @@ struct nfs_open_context {
}; };
struct nfs_open_dir_context { struct nfs_open_dir_context {
struct list_head list;
struct rpc_cred *cred; struct rpc_cred *cred;
unsigned long attr_gencount; unsigned long attr_gencount;
__u64 dir_cookie; __u64 dir_cookie;
...@@ -510,7 +511,6 @@ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); ...@@ -510,7 +511,6 @@ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
extern void nfs_wait_on_sillyrename(struct dentry *dentry); extern void nfs_wait_on_sillyrename(struct dentry *dentry);
extern void nfs_block_sillyrename(struct dentry *dentry); extern void nfs_block_sillyrename(struct dentry *dentry);
extern void nfs_unblock_sillyrename(struct dentry *dentry); extern void nfs_unblock_sillyrename(struct dentry *dentry);
extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);
/* /*
* linux/fs/nfs/write.c * linux/fs/nfs/write.c
......
...@@ -1402,6 +1402,7 @@ struct nfs_renamedata { ...@@ -1402,6 +1402,7 @@ struct nfs_renamedata {
struct inode *new_dir; struct inode *new_dir;
struct dentry *new_dentry; struct dentry *new_dentry;
struct nfs_fattr new_fattr; struct nfs_fattr new_fattr;
void (*complete)(struct rpc_task *, struct nfs_renamedata *);
}; };
struct nfs_access_entry; struct nfs_access_entry;
...@@ -1444,8 +1445,6 @@ struct nfs_rpc_ops { ...@@ -1444,8 +1445,6 @@ struct nfs_rpc_ops {
void (*unlink_setup) (struct rpc_message *, struct inode *dir); void (*unlink_setup) (struct rpc_message *, struct inode *dir);
void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *); void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
int (*unlink_done) (struct rpc_task *, struct inode *); int (*unlink_done) (struct rpc_task *, struct inode *);
int (*rename) (struct inode *, struct qstr *,
struct inode *, struct qstr *);
void (*rename_setup) (struct rpc_message *msg, struct inode *dir); void (*rename_setup) (struct rpc_message *msg, struct inode *dir);
void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
......
...@@ -32,7 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -32,7 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
#ifdef CONFIG_SUNRPC_BACKCHANNEL #ifdef CONFIG_SUNRPC_BACKCHANNEL
struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid);
void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied);
void xprt_free_bc_request(struct rpc_rqst *req); void xprt_free_bc_request(struct rpc_rqst *req);
int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
......
...@@ -212,39 +212,23 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) ...@@ -212,39 +212,23 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
} }
EXPORT_SYMBOL_GPL(xprt_destroy_backchannel); EXPORT_SYMBOL_GPL(xprt_destroy_backchannel);
/* static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid)
* One or more rpc_rqst structure have been preallocated during the
* backchannel setup. Buffer space for the send and private XDR buffers
* has been preallocated as well. Use xprt_alloc_bc_request to allocate
* to this request. Use xprt_free_bc_request to return it.
*
* We know that we're called in soft interrupt context, grab the spin_lock
* since there is no need to grab the bottom half spin_lock.
*
* Return an available rpc_rqst, otherwise NULL if non are available.
*/
struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt)
{ {
struct rpc_rqst *req; struct rpc_rqst *req = NULL;
dprintk("RPC: allocate a backchannel request\n"); dprintk("RPC: allocate a backchannel request\n");
spin_lock(&xprt->bc_pa_lock); if (list_empty(&xprt->bc_pa_list))
if (!list_empty(&xprt->bc_pa_list)) { goto not_found;
req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
rq_bc_pa_list);
list_del(&req->rq_bc_pa_list);
} else {
req = NULL;
}
spin_unlock(&xprt->bc_pa_lock);
if (req != NULL) { req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); rq_bc_pa_list);
req->rq_reply_bytes_recvd = 0; req->rq_reply_bytes_recvd = 0;
req->rq_bytes_sent = 0; req->rq_bytes_sent = 0;
memcpy(&req->rq_private_buf, &req->rq_rcv_buf, memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
sizeof(req->rq_private_buf)); sizeof(req->rq_private_buf));
} req->rq_xid = xid;
req->rq_connect_cookie = xprt->connect_cookie;
not_found:
dprintk("RPC: backchannel req=%p\n", req); dprintk("RPC: backchannel req=%p\n", req);
return req; return req;
} }
...@@ -259,6 +243,7 @@ void xprt_free_bc_request(struct rpc_rqst *req) ...@@ -259,6 +243,7 @@ void xprt_free_bc_request(struct rpc_rqst *req)
dprintk("RPC: free backchannel req=%p\n", req); dprintk("RPC: free backchannel req=%p\n", req);
req->rq_connect_cookie = xprt->connect_cookie - 1;
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
...@@ -281,7 +266,57 @@ void xprt_free_bc_request(struct rpc_rqst *req) ...@@ -281,7 +266,57 @@ void xprt_free_bc_request(struct rpc_rqst *req)
* may be reused by a new callback request. * may be reused by a new callback request.
*/ */
spin_lock_bh(&xprt->bc_pa_lock); spin_lock_bh(&xprt->bc_pa_lock);
list_add(&req->rq_bc_pa_list, &xprt->bc_pa_list); list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
spin_unlock_bh(&xprt->bc_pa_lock); spin_unlock_bh(&xprt->bc_pa_lock);
} }
/*
* One or more rpc_rqst structure have been preallocated during the
* backchannel setup. Buffer space for the send and private XDR buffers
* has been preallocated as well. Use xprt_alloc_bc_request to allocate
* to this request. Use xprt_free_bc_request to return it.
*
* We know that we're called in soft interrupt context, grab the spin_lock
* since there is no need to grab the bottom half spin_lock.
*
* Return an available rpc_rqst, otherwise NULL if non are available.
*/
struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid)
{
struct rpc_rqst *req;
spin_lock(&xprt->bc_pa_lock);
list_for_each_entry(req, &xprt->bc_pa_list, rq_bc_pa_list) {
if (req->rq_connect_cookie != xprt->connect_cookie)
continue;
if (req->rq_xid == xid)
goto found;
}
req = xprt_alloc_bc_request(xprt, xid);
found:
spin_unlock(&xprt->bc_pa_lock);
return req;
}
/*
* Add callback request to callback list. The callback
* service sleeps on the sv_cb_waitq waiting for new
* requests. Wake it up after adding enqueing the
* request.
*/
void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
{
struct rpc_xprt *xprt = req->rq_xprt;
struct svc_serv *bc_serv = xprt->bc_serv;
req->rq_private_buf.len = copied;
set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
dprintk("RPC: add callback request to list\n");
spin_lock(&bc_serv->sv_cb_lock);
list_del(&req->rq_bc_pa_list);
list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
wake_up(&bc_serv->sv_cb_waitq);
spin_unlock(&bc_serv->sv_cb_lock);
}
...@@ -1363,6 +1363,7 @@ rpc_restart_call_prepare(struct rpc_task *task) ...@@ -1363,6 +1363,7 @@ rpc_restart_call_prepare(struct rpc_task *task)
if (RPC_ASSASSINATED(task)) if (RPC_ASSASSINATED(task))
return 0; return 0;
task->tk_action = call_start; task->tk_action = call_start;
task->tk_status = 0;
if (task->tk_ops->rpc_call_prepare != NULL) if (task->tk_ops->rpc_call_prepare != NULL)
task->tk_action = rpc_prepare_task; task->tk_action = rpc_prepare_task;
return 1; return 1;
...@@ -1379,6 +1380,7 @@ rpc_restart_call(struct rpc_task *task) ...@@ -1379,6 +1380,7 @@ rpc_restart_call(struct rpc_task *task)
if (RPC_ASSASSINATED(task)) if (RPC_ASSASSINATED(task))
return 0; return 0;
task->tk_action = call_start; task->tk_action = call_start;
task->tk_status = 0;
return 1; return 1;
} }
EXPORT_SYMBOL_GPL(rpc_restart_call); EXPORT_SYMBOL_GPL(rpc_restart_call);
...@@ -1728,9 +1730,7 @@ call_bind_status(struct rpc_task *task) ...@@ -1728,9 +1730,7 @@ call_bind_status(struct rpc_task *task)
case -EPROTONOSUPPORT: case -EPROTONOSUPPORT:
dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n", dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
task->tk_pid); task->tk_pid);
task->tk_status = 0; goto retry_timeout;
task->tk_action = call_bind;
return;
case -ECONNREFUSED: /* connection problems */ case -ECONNREFUSED: /* connection problems */
case -ECONNRESET: case -ECONNRESET:
case -ECONNABORTED: case -ECONNABORTED:
...@@ -1756,6 +1756,7 @@ call_bind_status(struct rpc_task *task) ...@@ -1756,6 +1756,7 @@ call_bind_status(struct rpc_task *task)
return; return;
retry_timeout: retry_timeout:
task->tk_status = 0;
task->tk_action = call_timeout; task->tk_action = call_timeout;
} }
...@@ -1798,21 +1799,19 @@ call_connect_status(struct rpc_task *task) ...@@ -1798,21 +1799,19 @@ call_connect_status(struct rpc_task *task)
trace_rpc_connect_status(task, status); trace_rpc_connect_status(task, status);
task->tk_status = 0; task->tk_status = 0;
switch (status) { switch (status) {
/* if soft mounted, test if we've timed out */
case -ETIMEDOUT:
task->tk_action = call_timeout;
return;
case -ECONNREFUSED: case -ECONNREFUSED:
case -ECONNRESET: case -ECONNRESET:
case -ECONNABORTED: case -ECONNABORTED:
case -ENETUNREACH: case -ENETUNREACH:
case -EHOSTUNREACH: case -EHOSTUNREACH:
/* retry with existing socket, after a delay */
rpc_delay(task, 3*HZ);
if (RPC_IS_SOFTCONN(task)) if (RPC_IS_SOFTCONN(task))
break; break;
/* retry with existing socket, after a delay */
rpc_delay(task, 3*HZ);
case -EAGAIN: case -EAGAIN:
task->tk_action = call_bind; /* Check for timeouts before looping back to call_bind */
case -ETIMEDOUT:
task->tk_action = call_timeout;
return; return;
case 0: case 0:
clnt->cl_stats->netreconn++; clnt->cl_stats->netreconn++;
...@@ -2007,6 +2006,10 @@ call_status(struct rpc_task *task) ...@@ -2007,6 +2006,10 @@ call_status(struct rpc_task *task)
case -EHOSTDOWN: case -EHOSTDOWN:
case -EHOSTUNREACH: case -EHOSTUNREACH:
case -ENETUNREACH: case -ENETUNREACH:
if (RPC_IS_SOFTCONN(task)) {
rpc_exit(task, status);
break;
}
/* /*
* Delay any retries for 3 seconds, then handle as if it * Delay any retries for 3 seconds, then handle as if it
* were a timeout. * were a timeout.
......
...@@ -637,7 +637,8 @@ static void __rpc_queue_timer_fn(unsigned long ptr) ...@@ -637,7 +637,8 @@ static void __rpc_queue_timer_fn(unsigned long ptr)
static void __rpc_atrun(struct rpc_task *task) static void __rpc_atrun(struct rpc_task *task)
{ {
task->tk_status = 0; if (task->tk_status == -ETIMEDOUT)
task->tk_status = 0;
} }
/* /*
......
...@@ -649,9 +649,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) ...@@ -649,9 +649,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
break; break;
page_base = 0; page_base = 0;
} }
rqst->rq_rcv_buf.page_len = olen - copy_len; }
} else
rqst->rq_rcv_buf.page_len = 0;
if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) { if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) {
curlen = copy_len; curlen = copy_len;
......
...@@ -733,7 +733,7 @@ static void __exit xprt_rdma_cleanup(void) ...@@ -733,7 +733,7 @@ static void __exit xprt_rdma_cleanup(void)
{ {
int rc; int rc;
dprintk(KERN_INFO "RPCRDMA Module Removed, deregister RPC RDMA transport\n"); dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n");
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
if (sunrpc_table_header) { if (sunrpc_table_header) {
unregister_sysctl_table(sunrpc_table_header); unregister_sysctl_table(sunrpc_table_header);
...@@ -755,14 +755,14 @@ static int __init xprt_rdma_init(void) ...@@ -755,14 +755,14 @@ static int __init xprt_rdma_init(void)
if (rc) if (rc)
return rc; return rc;
dprintk(KERN_INFO "RPCRDMA Module Init, register RPC RDMA transport\n"); dprintk("RPCRDMA Module Init, register RPC RDMA transport\n");
dprintk(KERN_INFO "Defaults:\n"); dprintk("Defaults:\n");
dprintk(KERN_INFO "\tSlots %d\n" dprintk("\tSlots %d\n"
"\tMaxInlineRead %d\n\tMaxInlineWrite %d\n", "\tMaxInlineRead %d\n\tMaxInlineWrite %d\n",
xprt_rdma_slot_table_entries, xprt_rdma_slot_table_entries,
xprt_rdma_max_inline_read, xprt_rdma_max_inline_write); xprt_rdma_max_inline_read, xprt_rdma_max_inline_write);
dprintk(KERN_INFO "\tPadding %d\n\tMemreg %d\n", dprintk("\tPadding %d\n\tMemreg %d\n",
xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy); xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy);
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
......
...@@ -1306,41 +1306,29 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, ...@@ -1306,41 +1306,29 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt,
* If we're unable to obtain the rpc_rqst we schedule the closing of the * If we're unable to obtain the rpc_rqst we schedule the closing of the
* connection and return -1. * connection and return -1.
*/ */
static inline int xs_tcp_read_callback(struct rpc_xprt *xprt, static int xs_tcp_read_callback(struct rpc_xprt *xprt,
struct xdr_skb_reader *desc) struct xdr_skb_reader *desc)
{ {
struct sock_xprt *transport = struct sock_xprt *transport =
container_of(xprt, struct sock_xprt, xprt); container_of(xprt, struct sock_xprt, xprt);
struct rpc_rqst *req; struct rpc_rqst *req;
req = xprt_alloc_bc_request(xprt); /* Look up and lock the request corresponding to the given XID */
spin_lock(&xprt->transport_lock);
req = xprt_lookup_bc_request(xprt, transport->tcp_xid);
if (req == NULL) { if (req == NULL) {
spin_unlock(&xprt->transport_lock);
printk(KERN_WARNING "Callback slot table overflowed\n"); printk(KERN_WARNING "Callback slot table overflowed\n");
xprt_force_disconnect(xprt); xprt_force_disconnect(xprt);
return -1; return -1;
} }
req->rq_xid = transport->tcp_xid;
dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid));
xs_tcp_read_common(xprt, desc, req); xs_tcp_read_common(xprt, desc, req);
if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) { if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))
struct svc_serv *bc_serv = xprt->bc_serv; xprt_complete_bc_request(req, transport->tcp_copied);
spin_unlock(&xprt->transport_lock);
/*
* Add callback request to callback list. The callback
* service sleeps on the sv_cb_waitq waiting for new
* requests. Wake it up after adding enqueing the
* request.
*/
dprintk("RPC: add callback request to list\n");
spin_lock(&bc_serv->sv_cb_lock);
list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
spin_unlock(&bc_serv->sv_cb_lock);
wake_up(&bc_serv->sv_cb_waitq);
}
req->rq_private_buf.len = transport->tcp_copied;
return 0; return 0;
} }
......
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