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: NFSv4: fix delegated locking NFS: Ensure that the WRITE and COMMIT RPC calls are always uninterruptible NFS: Fix a race with the new commit code NFS: Ensure that writeback_single_inode() calls write_inode() when syncing NFS: Fix the mode calculation in nfs_find_open_context NFSv4: Fall back to ordinary lookup if nfs4_atomic_open() returns EISDIR
This commit is contained in:
commit
0fdfe5ad28
6 changed files with 39 additions and 23 deletions
|
@ -1294,7 +1294,8 @@ static int nfs4_init_server(struct nfs_server *server,
|
|||
|
||||
/* Initialise the client representation from the mount data */
|
||||
server->flags = data->flags;
|
||||
server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
|
||||
server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
|
||||
NFS_CAP_POSIX_LOCK;
|
||||
server->options = data->options;
|
||||
|
||||
/* Get a client record */
|
||||
|
|
|
@ -1025,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
|
|||
res = NULL;
|
||||
goto out;
|
||||
/* This turned out not to be a regular file */
|
||||
case -EISDIR:
|
||||
case -ENOTDIR:
|
||||
goto no_open;
|
||||
case -ELOOP:
|
||||
if (!(nd->intent.open.flags & O_NOFOLLOW))
|
||||
goto no_open;
|
||||
/* case -EISDIR: */
|
||||
/* case -EINVAL: */
|
||||
default:
|
||||
goto out;
|
||||
|
|
|
@ -623,10 +623,10 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
|
|||
list_for_each_entry(pos, &nfsi->open_files, list) {
|
||||
if (cred != NULL && pos->cred != cred)
|
||||
continue;
|
||||
if ((pos->mode & mode) == mode) {
|
||||
ctx = get_nfs_open_context(pos);
|
||||
break;
|
||||
}
|
||||
if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
|
||||
continue;
|
||||
ctx = get_nfs_open_context(pos);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
return ctx;
|
||||
|
|
|
@ -1523,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
|
|||
nfs_post_op_update_inode(dir, o_res->dir_attr);
|
||||
} else
|
||||
nfs_refresh_inode(dir, o_res->dir_attr);
|
||||
if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
|
||||
server->caps &= ~NFS_CAP_POSIX_LOCK;
|
||||
if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
|
||||
status = _nfs4_proc_open_confirm(data);
|
||||
if (status != 0)
|
||||
|
@ -1664,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
|
|||
status = PTR_ERR(state);
|
||||
if (IS_ERR(state))
|
||||
goto err_opendata_put;
|
||||
if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0)
|
||||
if (server->caps & NFS_CAP_POSIX_LOCK)
|
||||
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
|
||||
nfs4_opendata_put(opendata);
|
||||
nfs4_put_state_owner(sp);
|
||||
|
|
|
@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page)
|
|||
struct inode *inode = page->mapping->host;
|
||||
struct nfs_server *nfss = NFS_SERVER(inode);
|
||||
|
||||
page_cache_get(page);
|
||||
if (atomic_long_inc_return(&nfss->writeback) >
|
||||
NFS_CONGESTION_ON_THRESH) {
|
||||
set_bdi_congested(&nfss->backing_dev_info,
|
||||
|
@ -216,6 +217,7 @@ static void nfs_end_page_writeback(struct page *page)
|
|||
struct nfs_server *nfss = NFS_SERVER(inode);
|
||||
|
||||
end_page_writeback(page);
|
||||
page_cache_release(page);
|
||||
if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
|
||||
clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
|
||||
}
|
||||
|
@ -421,6 +423,7 @@ static void
|
|||
nfs_mark_request_dirty(struct nfs_page *req)
|
||||
{
|
||||
__set_page_dirty_nobuffers(req->wb_page);
|
||||
__mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
|
@ -660,9 +663,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
|
|||
req = nfs_setup_write_request(ctx, page, offset, count);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
nfs_mark_request_dirty(req);
|
||||
/* Update file length */
|
||||
nfs_grow_file(page, offset, count);
|
||||
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
|
||||
nfs_mark_request_dirty(req);
|
||||
nfs_clear_page_tag_locked(req);
|
||||
return 0;
|
||||
}
|
||||
|
@ -739,8 +744,6 @@ int nfs_updatepage(struct file *file, struct page *page,
|
|||
status = nfs_writepage_setup(ctx, page, offset, count);
|
||||
if (status < 0)
|
||||
nfs_set_pageerror(page);
|
||||
else
|
||||
__set_page_dirty_nobuffers(page);
|
||||
|
||||
dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n",
|
||||
status, (long long)i_size_read(inode));
|
||||
|
@ -749,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page,
|
|||
|
||||
static void nfs_writepage_release(struct nfs_page *req)
|
||||
{
|
||||
struct page *page = req->wb_page;
|
||||
|
||||
if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
|
||||
nfs_end_page_writeback(req->wb_page);
|
||||
if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req))
|
||||
nfs_inode_remove_request(req);
|
||||
} else
|
||||
nfs_end_page_writeback(req->wb_page);
|
||||
nfs_clear_page_tag_locked(req);
|
||||
nfs_end_page_writeback(page);
|
||||
}
|
||||
|
||||
static int flush_task_priority(int how)
|
||||
|
@ -779,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
|
|||
int how)
|
||||
{
|
||||
struct inode *inode = req->wb_context->path.dentry->d_inode;
|
||||
int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
|
||||
int priority = flush_task_priority(how);
|
||||
struct rpc_task *task;
|
||||
struct rpc_message msg = {
|
||||
|
@ -794,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
|
|||
.callback_ops = call_ops,
|
||||
.callback_data = data,
|
||||
.workqueue = nfsiod_workqueue,
|
||||
.flags = flags,
|
||||
.flags = RPC_TASK_ASYNC,
|
||||
.priority = priority,
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
/* Set up the RPC argument and reply structs
|
||||
* NB: take care not to mess about with data->commit et al. */
|
||||
|
@ -835,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
|
|||
(unsigned long long)data->args.offset);
|
||||
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
if (IS_ERR(task)) {
|
||||
ret = PTR_ERR(task);
|
||||
goto out;
|
||||
}
|
||||
if (how & FLUSH_SYNC) {
|
||||
ret = rpc_wait_for_completion_task(task);
|
||||
if (ret == 0)
|
||||
ret = task->tk_status;
|
||||
}
|
||||
rpc_put_task(task);
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If a nfs_flush_* function fails, it should remove reqs from @head and
|
||||
|
@ -847,9 +857,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
|
|||
*/
|
||||
static void nfs_redirty_request(struct nfs_page *req)
|
||||
{
|
||||
struct page *page = req->wb_page;
|
||||
|
||||
nfs_mark_request_dirty(req);
|
||||
nfs_end_page_writeback(req->wb_page);
|
||||
nfs_clear_page_tag_locked(req);
|
||||
nfs_end_page_writeback(page);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1084,16 +1096,15 @@ static void nfs_writeback_release_full(void *calldata)
|
|||
if (nfs_write_need_commit(data)) {
|
||||
memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
|
||||
nfs_mark_request_commit(req);
|
||||
nfs_end_page_writeback(page);
|
||||
dprintk(" marked for commit\n");
|
||||
goto next;
|
||||
}
|
||||
dprintk(" OK\n");
|
||||
remove_request:
|
||||
nfs_end_page_writeback(page);
|
||||
nfs_inode_remove_request(req);
|
||||
next:
|
||||
nfs_clear_page_tag_locked(req);
|
||||
nfs_end_page_writeback(page);
|
||||
}
|
||||
nfs_writedata_release(calldata);
|
||||
}
|
||||
|
@ -1207,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head,
|
|||
{
|
||||
struct nfs_page *first = nfs_list_entry(head->next);
|
||||
struct inode *inode = first->wb_context->path.dentry->d_inode;
|
||||
int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
|
||||
int priority = flush_task_priority(how);
|
||||
struct rpc_task *task;
|
||||
struct rpc_message msg = {
|
||||
|
@ -1222,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head,
|
|||
.callback_ops = &nfs_commit_ops,
|
||||
.callback_data = data,
|
||||
.workqueue = nfsiod_workqueue,
|
||||
.flags = flags,
|
||||
.flags = RPC_TASK_ASYNC,
|
||||
.priority = priority,
|
||||
};
|
||||
|
||||
|
@ -1252,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head,
|
|||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
if (how & FLUSH_SYNC)
|
||||
rpc_wait_for_completion_task(task);
|
||||
rpc_put_task(task);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -176,6 +176,7 @@ struct nfs_server {
|
|||
#define NFS_CAP_ATIME (1U << 11)
|
||||
#define NFS_CAP_CTIME (1U << 12)
|
||||
#define NFS_CAP_MTIME (1U << 13)
|
||||
#define NFS_CAP_POSIX_LOCK (1U << 14)
|
||||
|
||||
|
||||
/* maximum number of slots to use */
|
||||
|
|
Loading…
Reference in a new issue