Commit a9861b50 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFS: Don't clobber the attribute type in nfs_update_inode()
  NFS: Fix a umount race
  NFS: Fix an Oops when truncating a file
  NFS: Ensure that we handle NFS4ERR_STALE_STATEID correctly
  NFSv4.1: Don't call nfs4_schedule_state_recovery() unnecessarily
  NFSv4: Don't allow posix locking against servers that don't support it
  NFSv4: Ensure that the NFSv4 locking can recover from stateid errors
  NFS: Avoid warnings when CONFIG_NFS_V4=n
  NFS: Make nfs_commitdata_release static
  NFS: Try to commit unstable writes in nfs_release_page()
  NFS: Fix a reference leak in nfs_wb_cancel_page()
parents aa16cd8d 9b4b3513
...@@ -486,6 +486,8 @@ static int nfs_release_page(struct page *page, gfp_t gfp) ...@@ -486,6 +486,8 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
{ {
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
if (gfp & __GFP_WAIT)
nfs_wb_page(page->mapping->host, page);
/* If PagePrivate() is set, then the page is not freeable */ /* If PagePrivate() is set, then the page is not freeable */
if (PagePrivate(page)) if (PagePrivate(page))
return 0; return 0;
......
...@@ -1261,8 +1261,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1261,8 +1261,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (fattr->valid & NFS_ATTR_FATTR_MODE) { if (fattr->valid & NFS_ATTR_FATTR_MODE) {
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
umode_t newmode = inode->i_mode & S_IFMT;
newmode |= fattr->mode & S_IALLUGO;
inode->i_mode = newmode;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_mode = fattr->mode;
} }
} else if (server->caps & NFS_CAP_MODE) } else if (server->caps & NFS_CAP_MODE)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
......
...@@ -146,6 +146,7 @@ enum { ...@@ -146,6 +146,7 @@ enum {
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */
}; };
struct nfs4_state { struct nfs4_state {
...@@ -277,6 +278,7 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); ...@@ -277,6 +278,7 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
extern void nfs4_schedule_state_recovery(struct nfs_client *); extern void nfs4_schedule_state_recovery(struct nfs_client *);
extern void nfs4_schedule_state_manager(struct nfs_client *); extern void nfs4_schedule_state_manager(struct nfs_client *);
extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state);
extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
......
...@@ -249,19 +249,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, ...@@ -249,19 +249,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
if (state == NULL) if (state == NULL)
break; break;
nfs4_state_mark_reclaim_nograce(clp, state); nfs4_state_mark_reclaim_nograce(clp, state);
case -NFS4ERR_STALE_CLIENTID: goto do_state_recovery;
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED: if (state == NULL)
nfs4_schedule_state_recovery(clp);
ret = nfs4_wait_clnt_recover(clp);
if (ret == 0)
exception->retry = 1;
#if !defined(CONFIG_NFS_V4_1)
break;
#else /* !defined(CONFIG_NFS_V4_1) */
if (!nfs4_has_session(server->nfs_client))
break; break;
/* FALLTHROUGH */ nfs4_state_mark_reclaim_reboot(clp, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_EXPIRED:
goto do_state_recovery;
#if defined(CONFIG_NFS_V4_1)
case -NFS4ERR_BADSESSION: case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT: case -NFS4ERR_BADSLOT:
case -NFS4ERR_BAD_HIGH_SLOT: case -NFS4ERR_BAD_HIGH_SLOT:
...@@ -274,7 +270,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, ...@@ -274,7 +270,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
nfs4_schedule_state_recovery(clp); nfs4_schedule_state_recovery(clp);
exception->retry = 1; exception->retry = 1;
break; 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) {
/* We have retried a decent amount, time to /* We have retried a decent amount, time to
...@@ -293,6 +289,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, ...@@ -293,6 +289,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
} }
/* We failed to handle the error */ /* We failed to handle the error */
return nfs4_map_errors(ret); return nfs4_map_errors(ret);
do_state_recovery:
nfs4_schedule_state_recovery(clp);
ret = nfs4_wait_clnt_recover(clp);
if (ret == 0)
exception->retry = 1;
return ret;
} }
...@@ -1658,6 +1660,8 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in ...@@ -1658,6 +1660,8 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
status = PTR_ERR(state); status = PTR_ERR(state);
if (IS_ERR(state)) if (IS_ERR(state))
goto err_opendata_put; goto err_opendata_put;
if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0)
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
nfs4_opendata_put(opendata); nfs4_opendata_put(opendata);
nfs4_put_state_owner(sp); nfs4_put_state_owner(sp);
*res = state; *res = state;
...@@ -3422,15 +3426,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, ...@@ -3422,15 +3426,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
if (state == NULL) if (state == NULL)
break; break;
nfs4_state_mark_reclaim_nograce(clp, state); nfs4_state_mark_reclaim_nograce(clp, state);
case -NFS4ERR_STALE_CLIENTID: goto do_state_recovery;
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
if (state == NULL)
break;
nfs4_state_mark_reclaim_reboot(clp, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); goto do_state_recovery;
nfs4_schedule_state_recovery(clp);
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
task->tk_status = 0;
return -EAGAIN;
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
case -NFS4ERR_BADSESSION: case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT: case -NFS4ERR_BADSLOT:
...@@ -3458,6 +3461,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, ...@@ -3458,6 +3461,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
} }
task->tk_status = nfs4_map_errors(task->tk_status); task->tk_status = nfs4_map_errors(task->tk_status);
return 0; return 0;
do_state_recovery:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
nfs4_schedule_state_recovery(clp);
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
task->tk_status = 0;
return -EAGAIN;
} }
static int static int
...@@ -4088,6 +4098,28 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = { ...@@ -4088,6 +4098,28 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = {
.rpc_release = nfs4_lock_release, .rpc_release = nfs4_lock_release,
}; };
static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
{
struct nfs_client *clp = server->nfs_client;
struct nfs4_state *state = lsp->ls_state;
switch (error) {
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_EXPIRED:
if (new_lock_owner != 0 ||
(lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
nfs4_state_mark_reclaim_nograce(clp, state);
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
break;
case -NFS4ERR_STALE_STATEID:
if (new_lock_owner != 0 ||
(lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
nfs4_state_mark_reclaim_reboot(clp, state);
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
};
}
static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
{ {
struct nfs4_lockdata *data; struct nfs4_lockdata *data;
...@@ -4126,6 +4158,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ...@@ -4126,6 +4158,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
ret = nfs4_wait_for_completion_rpc_task(task); ret = nfs4_wait_for_completion_rpc_task(task);
if (ret == 0) { if (ret == 0) {
ret = data->rpc_status; ret = data->rpc_status;
if (ret)
nfs4_handle_setlk_error(data->server, data->lsp,
data->arg.new_lock_owner, ret);
} else } else
data->cancelled = 1; data->cancelled = 1;
rpc_put_task(task); rpc_put_task(task);
...@@ -4181,8 +4216,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock ...@@ -4181,8 +4216,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
{ {
struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_inode *nfsi = NFS_I(state->inode);
unsigned char fl_flags = request->fl_flags; unsigned char fl_flags = request->fl_flags;
int status; int status = -ENOLCK;
if ((fl_flags & FL_POSIX) &&
!test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
goto out;
/* Is this a delegated open? */ /* Is this a delegated open? */
status = nfs4_set_lock_state(state, request); status = nfs4_set_lock_state(state, request);
if (status != 0) if (status != 0)
......
...@@ -901,7 +901,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) ...@@ -901,7 +901,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp)
nfs4_schedule_state_manager(clp); nfs4_schedule_state_manager(clp);
} }
static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
{ {
set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
......
...@@ -176,6 +176,12 @@ void nfs_release_request(struct nfs_page *req) ...@@ -176,6 +176,12 @@ void nfs_release_request(struct nfs_page *req)
kref_put(&req->wb_kref, nfs_free_request); kref_put(&req->wb_kref, nfs_free_request);
} }
static int nfs_wait_bit_uninterruptible(void *word)
{
io_schedule();
return 0;
}
/** /**
* nfs_wait_on_request - Wait for a request to complete. * nfs_wait_on_request - Wait for a request to complete.
* @req: request to wait upon. * @req: request to wait upon.
...@@ -186,14 +192,9 @@ void nfs_release_request(struct nfs_page *req) ...@@ -186,14 +192,9 @@ void nfs_release_request(struct nfs_page *req)
int int
nfs_wait_on_request(struct nfs_page *req) nfs_wait_on_request(struct nfs_page *req)
{ {
int ret = 0; return wait_on_bit(&req->wb_flags, PG_BUSY,
nfs_wait_bit_uninterruptible,
if (!test_bit(PG_BUSY, &req->wb_flags)) TASK_UNINTERRUPTIBLE);
goto out;
ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY,
nfs_wait_bit_killable, TASK_KILLABLE);
out:
return ret;
} }
/** /**
......
...@@ -243,6 +243,7 @@ static int nfs_show_stats(struct seq_file *, struct vfsmount *); ...@@ -243,6 +243,7 @@ static int nfs_show_stats(struct seq_file *, struct vfsmount *);
static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
static int nfs_xdev_get_sb(struct file_system_type *fs_type, static int nfs_xdev_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static void nfs_put_super(struct super_block *);
static void nfs_kill_super(struct super_block *); static void nfs_kill_super(struct super_block *);
static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); static int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
...@@ -266,6 +267,7 @@ static const struct super_operations nfs_sops = { ...@@ -266,6 +267,7 @@ static const struct super_operations nfs_sops = {
.alloc_inode = nfs_alloc_inode, .alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode, .destroy_inode = nfs_destroy_inode,
.write_inode = nfs_write_inode, .write_inode = nfs_write_inode,
.put_super = nfs_put_super,
.statfs = nfs_statfs, .statfs = nfs_statfs,
.clear_inode = nfs_clear_inode, .clear_inode = nfs_clear_inode,
.umount_begin = nfs_umount_begin, .umount_begin = nfs_umount_begin,
...@@ -335,6 +337,7 @@ static const struct super_operations nfs4_sops = { ...@@ -335,6 +337,7 @@ static const struct super_operations nfs4_sops = {
.alloc_inode = nfs_alloc_inode, .alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode, .destroy_inode = nfs_destroy_inode,
.write_inode = nfs_write_inode, .write_inode = nfs_write_inode,
.put_super = nfs_put_super,
.statfs = nfs_statfs, .statfs = nfs_statfs,
.clear_inode = nfs4_clear_inode, .clear_inode = nfs4_clear_inode,
.umount_begin = nfs_umount_begin, .umount_begin = nfs_umount_begin,
...@@ -2257,6 +2260,17 @@ error_splat_super: ...@@ -2257,6 +2260,17 @@ error_splat_super:
goto out; goto out;
} }
/*
* Ensure that we unregister the bdi before kill_anon_super
* releases the device name
*/
static void nfs_put_super(struct super_block *s)
{
struct nfs_server *server = NFS_SB(s);
bdi_unregister(&server->backing_dev_info);
}
/* /*
* Destroy an NFS2/3 superblock * Destroy an NFS2/3 superblock
*/ */
...@@ -2265,7 +2279,6 @@ static void nfs_kill_super(struct super_block *s) ...@@ -2265,7 +2279,6 @@ static void nfs_kill_super(struct super_block *s)
struct nfs_server *server = NFS_SB(s); struct nfs_server *server = NFS_SB(s);
kill_anon_super(s); kill_anon_super(s);
bdi_unregister(&server->backing_dev_info);
nfs_fscache_release_super_cookie(s); nfs_fscache_release_super_cookie(s);
nfs_free_server(server); nfs_free_server(server);
} }
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
#include "callback.h" #include "callback.h"
#ifdef CONFIG_NFS_V4
static const int nfs_set_port_min = 0; static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535; static const int nfs_set_port_max = 65535;
#endif
static struct ctl_table_header *nfs_callback_sysctl_table; static struct ctl_table_header *nfs_callback_sysctl_table;
static ctl_table nfs_cb_sysctls[] = { static ctl_table nfs_cb_sysctls[] = {
......
...@@ -1233,7 +1233,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -1233,7 +1233,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
void nfs_commitdata_release(void *data) static void nfs_commitdata_release(void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_write_data *wdata = data;
...@@ -1541,6 +1541,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) ...@@ -1541,6 +1541,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
break; break;
} }
ret = nfs_wait_on_request(req); ret = nfs_wait_on_request(req);
nfs_release_request(req);
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
......
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