NFS bugfixes for Linux 3.7
- Fix a bunch of deadlock situations: * State recovery can deadlock if we fail to release sequence ids before scheduling the recovery thread. * Calling deactivate_super() from an RPC workqueue thread can deadlock because of the call to rpc_shutdown_client. - Display the device name correctly in /proc/*/mounts - Fix a number of incorrect error return values: * When NFSv3 mounts fail due to a timeout. * On NFSv4.1 backchannel setup failure * On NFSv4 open access checks - pnfs_find_alloc_layout() must check the layout pointer for NULL - Fix a regression in the legacy DNS resolved -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQlXRyAAoJEGcL54qWCgDy1G4QALUjERF6VBaDUVRVDe3cyrNr 1y5niKU19ysaXuNKtsGquVr3y72c0xyzCFLan8ZqJl1kXpYTDIyoDc0NBT3reffo T4rbw8SXVFVk+iVcJQgnFo5tblHVsVk+fvZPezBknaBb/uI/kxIbicZHHxvASyzM G0Ge/MC709x07tu3wJSyOtvD55j6bfpwbon6yjOKdN8/S2nOEsNOBjAunOWrKtsa 2v3uWC9APQqIF5z6dfhAVCEMRrQMame6W6b5LuY/MSQpLAwUUYeCGzjc1TMeWvnS n66iCqQ0TCVgJH+7fYnrzPm5uNk4Am2XhM3QY1B0j8zl73ZWIs4PfjdoBytLnqF+ SykNVUl72WqdJnWPCtk6LvoctyOsSMK5pJj4jadvNqDKgFkuRZkWb28bqux2OlHg ZCmnEZiew5tV+2anF6sgEaEhSyKNR/1h1ilXOy2TaV93qX+ec8tg+TE6C6YQR/R+ IoOoYD8Hbe/R/D76WK0xOOQbrXIQvKb1zvlIRx7W6d5gWpg9IceNLcBfCiF1GjPf 0PKxTbBSbSg44IRolPIprsZx6YzCI6wj2UzdPC7riozfZdSZ+T6Hh7z8rhhTjsHS D5emunX93kMp5QSSrw6EtdTkRJ++DB+cpjK5SP7UydHsWSGnKbd8eIv7viZu5J5O FLcHHWKIan9wQCslGQkO =NjEu -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - Fix a bunch of deadlock situations: * State recovery can deadlock if we fail to release sequence ids before scheduling the recovery thread. * Calling deactivate_super() from an RPC workqueue thread can deadlock because of the call to rpc_shutdown_client. - Display the device name correctly in /proc/*/mounts - Fix a number of incorrect error return values: * When NFSv3 mounts fail due to a timeout. * On NFSv4.1 backchannel setup failure * On NFSv4 open access checks - pnfs_find_alloc_layout() must check the layout pointer for NULL - Fix a regression in the legacy DNS resolved * tag 'nfs-for-3.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS4: nfs4_opendata_access should return errno NFSv4: Initialise the NFSv4.1 slot table highest_used_slotid correctly SUNRPC: return proper errno from backchannel_rqst NFS: add nfs_sb_deactive_async to avoid deadlock nfs: Show original device name verbatim in /proc/*/mount{s,info} nfsv3: Make v3 mounts fail with ETIMEDOUTs instead EIO on mountd timeouts nfs: Check whether a layout pointer is NULL before free it NFS: fix bug in legacy DNS resolver. NFSv4: nfs4_locku_done must release the sequence id NFSv4.1: We must release the sequence id when we fail to get a session slot NFS: Wait for session recovery to finish before returning
This commit is contained in:
commit
d4164973a0
|
@ -217,7 +217,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
|
char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
|
||||||
struct nfs_dns_ent key, *item;
|
struct nfs_dns_ent key, *item;
|
||||||
unsigned long ttl;
|
unsigned int ttl;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
@ -240,7 +240,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
|
||||||
key.namelen = len;
|
key.namelen = len;
|
||||||
memset(&key.h, 0, sizeof(key.h));
|
memset(&key.h, 0, sizeof(key.h));
|
||||||
|
|
||||||
ttl = get_expiry(&buf);
|
if (get_uint(&buf, &ttl) < 0)
|
||||||
|
goto out;
|
||||||
if (ttl == 0)
|
if (ttl == 0)
|
||||||
goto out;
|
goto out;
|
||||||
key.h.expiry_time = ttl + seconds_since_boot();
|
key.h.expiry_time = ttl + seconds_since_boot();
|
||||||
|
|
|
@ -685,7 +685,10 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
|
||||||
if (ctx->cred != NULL)
|
if (ctx->cred != NULL)
|
||||||
put_rpccred(ctx->cred);
|
put_rpccred(ctx->cred);
|
||||||
dput(ctx->dentry);
|
dput(ctx->dentry);
|
||||||
nfs_sb_deactive(sb);
|
if (is_sync)
|
||||||
|
nfs_sb_deactive(sb);
|
||||||
|
else
|
||||||
|
nfs_sb_deactive_async(sb);
|
||||||
kfree(ctx->mdsthreshold);
|
kfree(ctx->mdsthreshold);
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,10 +351,12 @@ extern int __init register_nfs_fs(void);
|
||||||
extern void __exit unregister_nfs_fs(void);
|
extern void __exit unregister_nfs_fs(void);
|
||||||
extern void nfs_sb_active(struct super_block *sb);
|
extern void nfs_sb_active(struct super_block *sb);
|
||||||
extern void nfs_sb_deactive(struct super_block *sb);
|
extern void nfs_sb_deactive(struct super_block *sb);
|
||||||
|
extern void nfs_sb_deactive_async(struct super_block *sb);
|
||||||
|
|
||||||
/* namespace.c */
|
/* namespace.c */
|
||||||
|
#define NFS_PATH_CANONICAL 1
|
||||||
extern char *nfs_path(char **p, struct dentry *dentry,
|
extern char *nfs_path(char **p, struct dentry *dentry,
|
||||||
char *buffer, ssize_t buflen);
|
char *buffer, ssize_t buflen, unsigned flags);
|
||||||
extern struct vfsmount *nfs_d_automount(struct path *path);
|
extern struct vfsmount *nfs_d_automount(struct path *path);
|
||||||
struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
|
struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
|
||||||
struct nfs_fh *, struct nfs_fattr *);
|
struct nfs_fh *, struct nfs_fattr *);
|
||||||
|
@ -498,7 +500,7 @@ static inline char *nfs_devname(struct dentry *dentry,
|
||||||
char *buffer, ssize_t buflen)
|
char *buffer, ssize_t buflen)
|
||||||
{
|
{
|
||||||
char *dummy;
|
char *dummy;
|
||||||
return nfs_path(&dummy, dentry, buffer, buflen);
|
return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info)
|
||||||
else
|
else
|
||||||
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
|
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
|
||||||
|
|
||||||
status = rpc_call_sync(mnt_clnt, &msg, 0);
|
status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
|
||||||
rpc_shutdown_client(mnt_clnt);
|
rpc_shutdown_client(mnt_clnt);
|
||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
|
|
|
@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||||
* @dentry - pointer to dentry
|
* @dentry - pointer to dentry
|
||||||
* @buffer - result buffer
|
* @buffer - result buffer
|
||||||
* @buflen - length of buffer
|
* @buflen - length of buffer
|
||||||
|
* @flags - options (see below)
|
||||||
*
|
*
|
||||||
* Helper function for constructing the server pathname
|
* Helper function for constructing the server pathname
|
||||||
* by arbitrary hashed dentry.
|
* by arbitrary hashed dentry.
|
||||||
|
@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||||
* This is mainly for use in figuring out the path on the
|
* This is mainly for use in figuring out the path on the
|
||||||
* server side when automounting on top of an existing partition
|
* server side when automounting on top of an existing partition
|
||||||
* and in generating /proc/mounts and friends.
|
* and in generating /proc/mounts and friends.
|
||||||
|
*
|
||||||
|
* Supported flags:
|
||||||
|
* NFS_PATH_CANONICAL: ensure there is exactly one slash after
|
||||||
|
* the original device (export) name
|
||||||
|
* (if unset, the original name is returned verbatim)
|
||||||
*/
|
*/
|
||||||
char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
|
char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
|
||||||
|
unsigned flags)
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
int namelen;
|
int namelen;
|
||||||
|
@ -74,7 +81,7 @@ rename_retry:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
goto rename_retry;
|
goto rename_retry;
|
||||||
}
|
}
|
||||||
if (*end != '/') {
|
if ((flags & NFS_PATH_CANONICAL) && *end != '/') {
|
||||||
if (--buflen < 0) {
|
if (--buflen < 0) {
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
@ -91,9 +98,11 @@ rename_retry:
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
namelen = strlen(base);
|
namelen = strlen(base);
|
||||||
/* Strip off excess slashes in base string */
|
if (flags & NFS_PATH_CANONICAL) {
|
||||||
while (namelen > 0 && base[namelen - 1] == '/')
|
/* Strip off excess slashes in base string */
|
||||||
namelen--;
|
while (namelen > 0 && base[namelen - 1] == '/')
|
||||||
|
namelen--;
|
||||||
|
}
|
||||||
buflen -= namelen;
|
buflen -= namelen;
|
||||||
if (buflen < 0) {
|
if (buflen < 0) {
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
|
|
@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end)
|
||||||
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
|
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||||
{
|
{
|
||||||
char *limit;
|
char *limit;
|
||||||
char *path = nfs_path(&limit, dentry, buffer, buflen);
|
char *path = nfs_path(&limit, dentry, buffer, buflen,
|
||||||
|
NFS_PATH_CANONICAL);
|
||||||
if (!IS_ERR(path)) {
|
if (!IS_ERR(path)) {
|
||||||
char *path_component = nfs_path_component(path, limit);
|
char *path_component = nfs_path_component(path, limit);
|
||||||
if (path_component)
|
if (path_component)
|
||||||
|
|
|
@ -339,8 +339,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
||||||
dprintk("%s ERROR: %d Reset session\n", __func__,
|
dprintk("%s ERROR: %d Reset session\n", __func__,
|
||||||
errorcode);
|
errorcode);
|
||||||
nfs4_schedule_session_recovery(clp->cl_session, errorcode);
|
nfs4_schedule_session_recovery(clp->cl_session, errorcode);
|
||||||
exception->retry = 1;
|
goto wait_on_recovery;
|
||||||
break;
|
|
||||||
#endif /* defined(CONFIG_NFS_V4_1) */
|
#endif /* defined(CONFIG_NFS_V4_1) */
|
||||||
case -NFS4ERR_FILE_OPEN:
|
case -NFS4ERR_FILE_OPEN:
|
||||||
if (exception->timeout > HZ) {
|
if (exception->timeout > HZ) {
|
||||||
|
@ -1572,9 +1571,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
||||||
data->timestamp = jiffies;
|
data->timestamp = jiffies;
|
||||||
if (nfs4_setup_sequence(data->o_arg.server,
|
if (nfs4_setup_sequence(data->o_arg.server,
|
||||||
&data->o_arg.seq_args,
|
&data->o_arg.seq_args,
|
||||||
&data->o_res.seq_res, task))
|
&data->o_res.seq_res,
|
||||||
return;
|
task) != 0)
|
||||||
rpc_call_start(task);
|
nfs_release_seqid(data->o_arg.seqid);
|
||||||
|
else
|
||||||
|
rpc_call_start(task);
|
||||||
return;
|
return;
|
||||||
unlock_no_action:
|
unlock_no_action:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
@ -1748,7 +1749,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
|
||||||
|
|
||||||
/* even though OPEN succeeded, access is denied. Close the file */
|
/* even though OPEN succeeded, access is denied. Close the file */
|
||||||
nfs4_close_state(state, fmode);
|
nfs4_close_state(state, fmode);
|
||||||
return -NFS4ERR_ACCESS;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2196,7 +2197,7 @@ static void nfs4_free_closedata(void *data)
|
||||||
nfs4_put_open_state(calldata->state);
|
nfs4_put_open_state(calldata->state);
|
||||||
nfs_free_seqid(calldata->arg.seqid);
|
nfs_free_seqid(calldata->arg.seqid);
|
||||||
nfs4_put_state_owner(sp);
|
nfs4_put_state_owner(sp);
|
||||||
nfs_sb_deactive(sb);
|
nfs_sb_deactive_async(sb);
|
||||||
kfree(calldata);
|
kfree(calldata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2296,9 +2297,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
||||||
if (nfs4_setup_sequence(NFS_SERVER(inode),
|
if (nfs4_setup_sequence(NFS_SERVER(inode),
|
||||||
&calldata->arg.seq_args,
|
&calldata->arg.seq_args,
|
||||||
&calldata->res.seq_res,
|
&calldata->res.seq_res,
|
||||||
task))
|
task) != 0)
|
||||||
goto out;
|
nfs_release_seqid(calldata->arg.seqid);
|
||||||
rpc_call_start(task);
|
else
|
||||||
|
rpc_call_start(task);
|
||||||
out:
|
out:
|
||||||
dprintk("%s: done!\n", __func__);
|
dprintk("%s: done!\n", __func__);
|
||||||
}
|
}
|
||||||
|
@ -4529,6 +4531,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
||||||
if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
|
if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
|
||||||
rpc_restart_call_prepare(task);
|
rpc_restart_call_prepare(task);
|
||||||
}
|
}
|
||||||
|
nfs_release_seqid(calldata->arg.seqid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
||||||
|
@ -4545,9 +4548,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
||||||
calldata->timestamp = jiffies;
|
calldata->timestamp = jiffies;
|
||||||
if (nfs4_setup_sequence(calldata->server,
|
if (nfs4_setup_sequence(calldata->server,
|
||||||
&calldata->arg.seq_args,
|
&calldata->arg.seq_args,
|
||||||
&calldata->res.seq_res, task))
|
&calldata->res.seq_res,
|
||||||
return;
|
task) != 0)
|
||||||
rpc_call_start(task);
|
nfs_release_seqid(calldata->arg.seqid);
|
||||||
|
else
|
||||||
|
rpc_call_start(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rpc_call_ops nfs4_locku_ops = {
|
static const struct rpc_call_ops nfs4_locku_ops = {
|
||||||
|
@ -4692,7 +4697,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
||||||
/* Do we need to do an open_to_lock_owner? */
|
/* Do we need to do an open_to_lock_owner? */
|
||||||
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
|
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
|
||||||
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
|
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
|
||||||
return;
|
goto out_release_lock_seqid;
|
||||||
data->arg.open_stateid = &state->stateid;
|
data->arg.open_stateid = &state->stateid;
|
||||||
data->arg.new_lock_owner = 1;
|
data->arg.new_lock_owner = 1;
|
||||||
data->res.open_seqid = data->arg.open_seqid;
|
data->res.open_seqid = data->arg.open_seqid;
|
||||||
|
@ -4701,10 +4706,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
||||||
data->timestamp = jiffies;
|
data->timestamp = jiffies;
|
||||||
if (nfs4_setup_sequence(data->server,
|
if (nfs4_setup_sequence(data->server,
|
||||||
&data->arg.seq_args,
|
&data->arg.seq_args,
|
||||||
&data->res.seq_res, task))
|
&data->res.seq_res,
|
||||||
|
task) == 0) {
|
||||||
|
rpc_call_start(task);
|
||||||
return;
|
return;
|
||||||
rpc_call_start(task);
|
}
|
||||||
dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
|
nfs_release_seqid(data->arg.open_seqid);
|
||||||
|
out_release_lock_seqid:
|
||||||
|
nfs_release_seqid(data->arg.lock_seqid);
|
||||||
|
dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
|
static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
|
||||||
|
@ -5667,7 +5677,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,
|
||||||
tbl->slots = new;
|
tbl->slots = new;
|
||||||
tbl->max_slots = max_slots;
|
tbl->max_slots = max_slots;
|
||||||
}
|
}
|
||||||
tbl->highest_used_slotid = -1; /* no slot is currently used */
|
tbl->highest_used_slotid = NFS4_NO_SLOT;
|
||||||
for (i = 0; i < tbl->max_slots; i++)
|
for (i = 0; i < tbl->max_slots; i++)
|
||||||
tbl->slots[i].seq_nr = ivalue;
|
tbl->slots[i].seq_nr = ivalue;
|
||||||
spin_unlock(&tbl->slot_tbl_lock);
|
spin_unlock(&tbl->slot_tbl_lock);
|
||||||
|
|
|
@ -925,8 +925,8 @@ pnfs_find_alloc_layout(struct inode *ino,
|
||||||
if (likely(nfsi->layout == NULL)) { /* Won the race? */
|
if (likely(nfsi->layout == NULL)) { /* Won the race? */
|
||||||
nfsi->layout = new;
|
nfsi->layout = new;
|
||||||
return new;
|
return new;
|
||||||
}
|
} else if (new != NULL)
|
||||||
pnfs_free_layout_hdr(new);
|
pnfs_free_layout_hdr(new);
|
||||||
out_existing:
|
out_existing:
|
||||||
pnfs_get_layout_hdr(nfsi->layout);
|
pnfs_get_layout_hdr(nfsi->layout);
|
||||||
return nfsi->layout;
|
return nfsi->layout;
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/nsproxy.h>
|
#include <linux/nsproxy.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
@ -415,6 +416,54 @@ void nfs_sb_deactive(struct super_block *sb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_sb_deactive);
|
EXPORT_SYMBOL_GPL(nfs_sb_deactive);
|
||||||
|
|
||||||
|
static int nfs_deactivate_super_async_work(void *ptr)
|
||||||
|
{
|
||||||
|
struct super_block *sb = ptr;
|
||||||
|
|
||||||
|
deactivate_super(sb);
|
||||||
|
module_put_and_exit(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* same effect as deactivate_super, but will do final unmount in kthread
|
||||||
|
* context
|
||||||
|
*/
|
||||||
|
static void nfs_deactivate_super_async(struct super_block *sb)
|
||||||
|
{
|
||||||
|
struct task_struct *task;
|
||||||
|
char buf[INET6_ADDRSTRLEN + 1];
|
||||||
|
struct nfs_server *server = NFS_SB(sb);
|
||||||
|
struct nfs_client *clp = server->nfs_client;
|
||||||
|
|
||||||
|
if (!atomic_add_unless(&sb->s_active, -1, 1)) {
|
||||||
|
rcu_read_lock();
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
__module_get(THIS_MODULE);
|
||||||
|
task = kthread_run(nfs_deactivate_super_async_work, sb,
|
||||||
|
"%s-deactivate-super", buf);
|
||||||
|
if (IS_ERR(task)) {
|
||||||
|
pr_err("%s: kthread_run: %ld\n",
|
||||||
|
__func__, PTR_ERR(task));
|
||||||
|
/* make synchronous call and hope for the best */
|
||||||
|
deactivate_super(sb);
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfs_sb_deactive_async(struct super_block *sb)
|
||||||
|
{
|
||||||
|
struct nfs_server *server = NFS_SB(sb);
|
||||||
|
|
||||||
|
if (atomic_dec_and_test(&server->active))
|
||||||
|
nfs_deactivate_super_async(sb);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nfs_sb_deactive_async);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deliver file system statistics to userspace
|
* Deliver file system statistics to userspace
|
||||||
*/
|
*/
|
||||||
|
@ -771,7 +820,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root)
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (!page)
|
if (!page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
devname = nfs_path(&dummy, root, page, PAGE_SIZE);
|
devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0);
|
||||||
if (IS_ERR(devname))
|
if (IS_ERR(devname))
|
||||||
err = PTR_ERR(devname);
|
err = PTR_ERR(devname);
|
||||||
else
|
else
|
||||||
|
|
|
@ -95,7 +95,7 @@ static void nfs_async_unlink_release(void *calldata)
|
||||||
|
|
||||||
nfs_dec_sillycount(data->dir);
|
nfs_dec_sillycount(data->dir);
|
||||||
nfs_free_unlinkdata(data);
|
nfs_free_unlinkdata(data);
|
||||||
nfs_sb_deactive(sb);
|
nfs_sb_deactive_async(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
|
static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
|
||||||
|
|
|
@ -172,7 +172,7 @@ out_free:
|
||||||
xprt_free_allocation(req);
|
xprt_free_allocation(req);
|
||||||
|
|
||||||
dprintk("RPC: setup backchannel transport failed\n");
|
dprintk("RPC: setup backchannel transport failed\n");
|
||||||
return -1;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xprt_setup_backchannel);
|
EXPORT_SYMBOL_GPL(xprt_setup_backchannel);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue