* nfs_direct_read_seg - Read in one iov segment. Generate separate
* read RPCs for each "rsize" bytes.
* @inode: target inode
- * @file: target file (may be NULL)
+ * @ctx: target file open context
* user_addr: starting address of this segment of user's buffer
* count: size of this segment
* file_offset: offset in file to begin the operation
* nr_pages: size of pages array
*/
static int
-nfs_direct_read_seg(struct inode *inode, struct file *file,
+nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
unsigned long user_addr, size_t count, loff_t file_offset,
struct page **pages, int nr_pages)
{
int curpage = 0;
struct nfs_read_data rdata = {
.inode = inode,
+ .cred = ctx->cred,
.args = {
.fh = NFS_FH(inode),
- .lockowner = current->files,
+ .lockowner = ctx->lockowner,
+ .state = ctx->state,
},
.res = {
.fattr = &rdata.fattr,
user_addr + tot_bytes, rdata.args.pgbase, curpage);
lock_kernel();
- result = NFS_PROTO(inode)->read(&rdata, file);
+ result = NFS_PROTO(inode)->read(&rdata);
unlock_kernel();
if (result <= 0) {
* nfs_direct_read - For each iov segment, map the user's buffer
* then generate read RPCs.
* @inode: target inode
- * @file: target file (may be NULL)
+ * @ctx: target file open context
* @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation
* nr_segs: size of iovec array
* server.
*/
static ssize_t
-nfs_direct_read(struct inode *inode, struct file *file,
+nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx,
const struct iovec *iov, loff_t file_offset,
unsigned long nr_segs)
{
return page_count;
}
- result = nfs_direct_read_seg(inode, file, user_addr, size,
+ result = nfs_direct_read_seg(inode, ctx, user_addr, size,
file_offset, pages, page_count);
nfs_free_user_pages(pages, page_count, 1);
* nfs_direct_write_seg - Write out one iov segment. Generate separate
* write RPCs for each "wsize" bytes, then commit.
* @inode: target inode
- * @file: target file (may be NULL)
+ * @ctx: target file open context
* user_addr: starting address of this segment of user's buffer
* count: size of this segment
* file_offset: offset in file to begin the operation
* nr_pages: size of pages array
*/
static int
-nfs_direct_write_seg(struct inode *inode, struct file *file,
+nfs_direct_write_seg(struct inode *inode, struct nfs_open_context *ctx,
unsigned long user_addr, size_t count, loff_t file_offset,
struct page **pages, int nr_pages)
{
struct nfs_writeverf first_verf;
struct nfs_write_data wdata = {
.inode = inode,
+ .cred = ctx->cred,
.args = {
.fh = NFS_FH(inode),
- .lockowner = current->files,
+ .lockowner = ctx->lockowner,
+ .state = ctx->state,
},
.res = {
.fattr = &wdata.fattr,
user_addr + tot_bytes, wdata.args.pgbase, curpage);
lock_kernel();
- result = NFS_PROTO(inode)->write(&wdata, file);
+ result = NFS_PROTO(inode)->write(&wdata);
unlock_kernel();
if (result <= 0) {
wdata.args.offset = file_offset;
lock_kernel();
- result = NFS_PROTO(inode)->commit(&wdata, file);
+ result = NFS_PROTO(inode)->commit(&wdata);
unlock_kernel();
if (result < 0 || memcmp(&first_verf.verifier,
* nfs_direct_write - For each iov segment, map the user's buffer
* then generate write and commit RPCs.
* @inode: target inode
- * @file: target file (may be NULL)
+ * @ctx: target file open context
* @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation
* nr_segs: size of iovec array
* that non-direct readers might access, so they will pick up these
* writes immediately.
*/
-static ssize_t
-nfs_direct_write(struct inode *inode, struct file *file,
+static int nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx,
const struct iovec *iov, loff_t file_offset,
unsigned long nr_segs)
{
return page_count;
}
- result = nfs_direct_write_seg(inode, file, user_addr, size,
+ result = nfs_direct_write_seg(inode, ctx, user_addr, size,
file_offset, pages, page_count);
nfs_free_user_pages(pages, page_count, 0);
{
ssize_t result = -EINVAL;
struct file *file = iocb->ki_filp;
+ struct nfs_open_context *ctx;
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
if (!is_sync_kiocb(iocb))
return result;
+ ctx = (struct nfs_open_context *)file->private_data;
switch (rw) {
case READ:
dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n",
dentry->d_name.name, file_offset, nr_segs);
- result = nfs_direct_read(inode, file, iov,
+ result = nfs_direct_read(inode, ctx, iov,
file_offset, nr_segs);
break;
case WRITE:
dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n",
dentry->d_name.name, file_offset, nr_segs);
- result = nfs_direct_write(inode, file, iov,
+ result = nfs_direct_write(inode, ctx, iov,
file_offset, nr_segs);
break;
default:
ssize_t retval = -EINVAL;
loff_t *ppos = &iocb->ki_pos;
struct file *file = iocb->ki_filp;
+ struct nfs_open_context *ctx =
+ (struct nfs_open_context *) file->private_data;
struct dentry *dentry = file->f_dentry;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
goto out;
}
- retval = nfs_direct_read(inode, file, &iov, pos, 1);
+ retval = nfs_direct_read(inode, ctx, &iov, pos, 1);
if (retval > 0)
*ppos = pos + retval;
loff_t *ppos = &iocb->ki_pos;
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
struct file *file = iocb->ki_filp;
+ struct nfs_open_context *ctx =
+ (struct nfs_open_context *) file->private_data;
struct dentry *dentry = file->f_dentry;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
goto out;
}
- retval = nfs_direct_write(inode, file, &iov, pos, 1);
+ retval = nfs_direct_write(inode, ctx, &iov, pos, 1);
if (mapping->nrpages)
invalidate_inode_pages2(mapping);
if (retval > 0)
static int
nfs_file_flush(struct file *file)
{
+ struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
struct inode *inode = file->f_dentry->d_inode;
int status;
/* Ensure that data+attribute caches are up to date after close() */
status = nfs_wb_all(inode);
if (!status) {
- status = file->f_error;
- file->f_error = 0;
+ status = ctx->error;
+ ctx->error = 0;
if (!status)
__nfs_revalidate_inode(NFS_SERVER(inode), inode);
}
static int
nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
+ struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
struct inode *inode = dentry->d_inode;
int status;
lock_kernel();
status = nfs_wb_all(inode);
if (!status) {
- status = file->f_error;
- file->f_error = 0;
+ status = ctx->error;
+ ctx->error = 0;
}
unlock_kernel();
return status;
{
dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
+ nfs_wb_all(inode);
/*
- * The following can never actually happen...
+ * The following should never happen...
*/
if (nfs_have_writebacks(inode)) {
printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
nfs_clear_inode(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
- struct rpc_cred *cred = nfsi->mm_cred;
+ struct rpc_cred *cred;
- if (cred)
- put_rpccred(cred);
+ nfs_wb_all(inode);
+ BUG_ON (!list_empty(&nfsi->open_files));
cred = nfsi->cache_access.cred;
if (cred)
put_rpccred(cred);
return err;
}
+struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred)
+{
+ struct nfs_open_context *ctx;
+
+ ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx != NULL) {
+ atomic_set(&ctx->count, 1);
+ ctx->dentry = dget(dentry);
+ ctx->cred = get_rpccred(cred);
+ ctx->state = NULL;
+ ctx->lockowner = current->files;
+ ctx->error = 0;
+ init_waitqueue_head(&ctx->waitq);
+ }
+ return ctx;
+}
+
+struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
+{
+ if (ctx != NULL)
+ atomic_inc(&ctx->count);
+ return ctx;
+}
+
+void put_nfs_open_context(struct nfs_open_context *ctx)
+{
+ if (atomic_dec_and_test(&ctx->count)) {
+ if (ctx->state != NULL)
+ nfs4_close_state(ctx->state, ctx->mode);
+ if (ctx->cred != NULL)
+ put_rpccred(ctx->cred);
+ dput(ctx->dentry);
+ kfree(ctx);
+ }
+}
+
/*
* Ensure that mmap has a recent RPC credential for use when writing out
* shared pages
*/
-void
-nfs_set_mmcred(struct inode *inode, struct rpc_cred *cred)
+void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
- struct rpc_cred **p = &NFS_I(inode)->mm_cred,
- *oldcred = *p;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
- *p = get_rpccred(cred);
- if (oldcred)
- put_rpccred(oldcred);
+ filp->private_data = get_nfs_open_context(ctx);
+ spin_lock(&inode->i_lock);
+ list_add(&ctx->list, &nfsi->open_files);
+ spin_unlock(&inode->i_lock);
+}
+
+struct nfs_open_context *nfs_find_open_context(struct inode *inode, int mode)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_open_context *pos, *ctx = NULL;
+
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(pos, &nfsi->open_files, list) {
+ if ((pos->mode & mode) == mode) {
+ ctx = get_nfs_open_context(pos);
+ break;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ return ctx;
+}
+
+void nfs_file_clear_open_context(struct file *filp)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
+
+ if (ctx) {
+ filp->private_data = NULL;
+ spin_lock(&inode->i_lock);
+ list_del(&ctx->list);
+ spin_unlock(&inode->i_lock);
+ put_nfs_open_context(ctx);
+ }
}
/*
- * These are probably going to contain hooks for
- * allocating and releasing RPC credentials for
- * the file. I'll have to think about Tronds patch
- * a bit more..
+ * These allocate and release file read/write context information.
*/
int nfs_open(struct inode *inode, struct file *filp)
{
- struct rpc_auth *auth;
+ struct nfs_open_context *ctx;
struct rpc_cred *cred;
- auth = NFS_CLIENT(inode)->cl_auth;
- cred = rpcauth_lookupcred(auth, 0);
- filp->private_data = cred;
- if ((filp->f_mode & FMODE_WRITE) != 0) {
- nfs_set_mmcred(inode, cred);
+ if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
+ return -ENOMEM;
+ ctx = alloc_nfs_open_context(filp->f_dentry, cred);
+ put_rpccred(cred);
+ if (ctx == NULL)
+ return -ENOMEM;
+ ctx->mode = filp->f_mode;
+ nfs_file_set_open_context(filp, ctx);
+ put_nfs_open_context(ctx);
+ if ((filp->f_mode & FMODE_WRITE) != 0)
nfs_begin_data_update(inode);
- }
return 0;
}
int nfs_release(struct inode *inode, struct file *filp)
{
- struct rpc_cred *cred;
-
- lock_kernel();
if ((filp->f_mode & FMODE_WRITE) != 0)
nfs_end_data_update(inode);
- cred = nfs_file_cred(filp);
- if (cred)
- put_rpccred(cred);
- unlock_kernel();
+ nfs_file_clear_open_context(filp);
return 0;
}
{
struct nfs_inode *nfsi = NFS_I(inode);
+ /* First call standard NFS clear_inode() code */
+ nfs_clear_inode(inode);
+ /* Now clear out any remaining state */
while (!list_empty(&nfsi->open_states)) {
struct nfs4_state *state;
BUG_ON(atomic_read(&state->count) != 1);
nfs4_close_state(state, state->state);
}
- /* Now call standard NFS clear_inode() code */
- nfs_clear_inode(inode);
}
if (!nfsi)
return NULL;
nfsi->flags = 0;
- nfsi->mm_cred = NULL;
nfs4_zero_state(nfsi);
return &nfsi->vfs_inode;
}
spin_lock_init(&nfsi->req_lock);
INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit);
+ INIT_LIST_HEAD(&nfsi->open_files);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0;
return 1;
}
-static struct rpc_cred *
-nfs_cred(struct inode *inode, struct file *filp)
-{
- struct rpc_cred *cred = NULL;
-
- if (filp)
- cred = (struct rpc_cred *)filp->private_data;
- if (!cred)
- cred = NFS_I(inode)->mm_cred;
- return cred;
-}
-
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
return status;
}
-static int
-nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
+static int nfs3_proc_read(struct nfs_read_data *rdata)
{
int flags = rdata->flags;
struct inode * inode = rdata->inode;
.rpc_proc = &nfs3_procedures[NFS3PROC_READ],
.rpc_argp = &rdata->args,
.rpc_resp = &rdata->res,
+ .rpc_cred = rdata->cred,
};
int status;
dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset);
fattr->valid = 0;
- msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
if (status >= 0)
nfs_refresh_inode(inode, fattr);
return status;
}
-static int
-nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
+static int nfs3_proc_write(struct nfs_write_data *wdata)
{
int rpcflags = wdata->flags;
struct inode * inode = wdata->inode;
.rpc_proc = &nfs3_procedures[NFS3PROC_WRITE],
.rpc_argp = &wdata->args,
.rpc_resp = &wdata->res,
+ .rpc_cred = wdata->cred,
};
int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset);
fattr->valid = 0;
- msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
if (status >= 0)
nfs_refresh_inode(inode, fattr);
return status < 0? status : wdata->res.count;
}
-static int
-nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
+static int nfs3_proc_commit(struct nfs_write_data *cdata)
{
struct inode * inode = cdata->inode;
struct nfs_fattr * fattr = cdata->res.fattr;
.rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT],
.rpc_argp = &cdata->args,
.rpc_resp = &cdata->res,
+ .rpc_cred = cdata->cred,
};
int status;
dprintk("NFS call commit %d @ %Ld\n", cdata->args.count,
(long long) cdata->args.offset);
fattr->valid = 0;
- msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status >= 0)
nfs_refresh_inode(inode, fattr);
rpc_call_setup(task, &msg, 0);
}
-/*
- * Set up the nfspage struct with the right credentials
- */
-void
-nfs3_request_init(struct nfs_page *req, struct file *filp)
-{
- req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp));
-}
-
-static int
-nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
-{
- if (req->wb_file != filp)
- return 0;
- if (req->wb_page != page)
- return 0;
- if (req->wb_cred != nfs_file_cred(filp))
- return 0;
- return 1;
-}
-
static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
.commit_setup = nfs3_proc_commit_setup,
.file_open = nfs_open,
.file_release = nfs_release,
- .request_init = nfs3_request_init,
- .request_compatible = nfs3_request_compatible,
.lock = nfs3_proc_lock,
};
return err;
}
-static int _nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
+static int _nfs4_proc_read(struct nfs_read_data *rdata)
{
int flags = rdata->flags;
struct inode *inode = rdata->inode;
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ],
.rpc_argp = &rdata->args,
.rpc_resp = &rdata->res,
+ .rpc_cred = rdata->cred,
};
unsigned long timestamp = jiffies;
int status;
dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset);
- /*
- * Try first to use O_RDONLY, then O_RDWR stateid.
- */
- if (filp) {
- struct nfs4_state *state;
- state = (struct nfs4_state *)filp->private_data;
- rdata->args.state = state;
- msg.rpc_cred = state->owner->so_cred;
- } else {
- rdata->args.state = NULL;
- msg.rpc_cred = NFS_I(inode)->mm_cred;
- }
-
fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, flags);
if (!status)
return status;
}
-static int nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
+static int nfs4_proc_read(struct nfs_read_data *rdata)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(rdata->inode),
- _nfs4_proc_read(rdata, filp),
+ _nfs4_proc_read(rdata),
&exception);
} while (exception.retry);
return err;
}
-static int _nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
+static int _nfs4_proc_write(struct nfs_write_data *wdata)
{
int rpcflags = wdata->flags;
struct inode *inode = wdata->inode;
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE],
.rpc_argp = &wdata->args,
.rpc_resp = &wdata->res,
+ .rpc_cred = wdata->cred,
};
int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset);
- /*
- * Try first to use O_WRONLY, then O_RDWR stateid.
- */
- if (filp) {
- struct nfs4_state *state;
- state = (struct nfs4_state *)filp->private_data;
- wdata->args.state = state;
- msg.rpc_cred = state->owner->so_cred;
- } else {
- wdata->args.state = NULL;
- msg.rpc_cred = NFS_I(inode)->mm_cred;
- }
-
fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, rpcflags);
dprintk("NFS reply write: %d\n", status);
return status;
}
-static int nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
+static int nfs4_proc_write(struct nfs_write_data *wdata)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(wdata->inode),
- _nfs4_proc_write(wdata, filp),
+ _nfs4_proc_write(wdata),
&exception);
} while (exception.retry);
return err;
}
-static int _nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
+static int _nfs4_proc_commit(struct nfs_write_data *cdata)
{
struct inode *inode = cdata->inode;
struct nfs_fattr *fattr = cdata->res.fattr;
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
.rpc_argp = &cdata->args,
.rpc_resp = &cdata->res,
+ .rpc_cred = cdata->cred,
};
int status;
dprintk("NFS call commit %d @ %Ld\n", cdata->args.count,
(long long) cdata->args.offset);
- /*
- * Try first to use O_WRONLY, then O_RDWR stateid.
- */
- if (filp)
- msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred;
- else
- msg.rpc_cred = NFS_I(inode)->mm_cred;
-
fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, 0);
dprintk("NFS reply commit: %d\n", status);
return status;
}
-static int nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
+static int nfs4_proc_commit(struct nfs_write_data *cdata)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(cdata->inode),
- _nfs4_proc_commit(cdata, filp),
+ _nfs4_proc_commit(cdata),
&exception);
} while (exception.retry);
return err;
nfs4_proc_file_open(struct inode *inode, struct file *filp)
{
struct dentry *dentry = filp->f_dentry;
- struct nfs4_state *state;
+ struct nfs_open_context *ctx;
+ struct nfs4_state *state = NULL;
struct rpc_cred *cred;
+ int status = -ENOMEM;
dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n",
(int)dentry->d_parent->d_name.len,
/* Find our open stateid */
cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
- state = nfs4_find_state(inode, cred, filp->f_mode);
+ if (unlikely(cred == NULL))
+ return -ENOMEM;
+ ctx = alloc_nfs_open_context(dentry, cred);
put_rpccred(cred);
- if (state == NULL) {
- printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
- return -EIO; /* ERACE actually */
- }
+ if (unlikely(ctx == NULL))
+ return -ENOMEM;
+ status = -EIO; /* ERACE actually */
+ state = nfs4_find_state(inode, cred, filp->f_mode);
+ if (unlikely(state == NULL))
+ goto no_state;
+ ctx->state = state;
nfs4_close_state(state, filp->f_mode);
- if (filp->f_mode & FMODE_WRITE) {
- lock_kernel();
- nfs_set_mmcred(inode, state->owner->so_cred);
+ ctx->mode = filp->f_mode;
+ nfs_file_set_open_context(filp, ctx);
+ put_nfs_open_context(ctx);
+ if (filp->f_mode & FMODE_WRITE)
nfs_begin_data_update(inode);
- unlock_kernel();
- }
- filp->private_data = state;
return 0;
+no_state:
+ printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
+ put_nfs_open_context(ctx);
+ return status;
}
/*
static int
nfs4_proc_file_release(struct inode *inode, struct file *filp)
{
- struct nfs4_state *state = (struct nfs4_state *)filp->private_data;
-
- if (state)
- nfs4_close_state(state, filp->f_mode);
- if (filp->f_mode & FMODE_WRITE) {
- lock_kernel();
+ if (filp->f_mode & FMODE_WRITE)
nfs_end_data_update(inode);
- unlock_kernel();
- }
+ nfs_file_clear_open_context(filp);
return 0;
}
-/*
- * Set up the nfspage struct with the right state info and credentials
- */
-static void
-nfs4_request_init(struct nfs_page *req, struct file *filp)
-{
- struct nfs4_state *state;
-
- if (!filp) {
- req->wb_cred = get_rpccred(NFS_I(req->wb_inode)->mm_cred);
- req->wb_state = NULL;
- return;
- }
- state = (struct nfs4_state *)filp->private_data;
- req->wb_state = state;
- req->wb_cred = get_rpccred(state->owner->so_cred);
- req->wb_lockowner = current->files;
-}
-
static int
nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
{
return nfs4_map_errors(ret);
}
-
-static int
-nfs4_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
-{
- struct nfs4_state *state = NULL;
- struct rpc_cred *cred = NULL;
-
- if (req->wb_file != filp)
- return 0;
- if (req->wb_page != page)
- return 0;
- state = (struct nfs4_state *)filp->private_data;
- if (req->wb_state != state)
- return 0;
- if (req->wb_lockowner != current->files)
- return 0;
- cred = state->owner->so_cred;
- if (req->wb_cred != cred)
- return 0;
- return 1;
-}
-
int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port)
{
static nfs4_verifier sc_verifier;
static int
nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
{
+ struct nfs_open_context *ctx;
struct nfs4_state *state;
unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
int status;
/* verify open state */
- state = (struct nfs4_state *)filp->private_data;
- BUG_ON(!state);
+ ctx = (struct nfs_open_context *)filp->private_data;
+ state = ctx->state;
if (request->fl_start < 0 || request->fl_end < 0)
return -EINVAL;
.commit_setup = nfs4_proc_commit_setup,
.file_open = nfs4_proc_file_open,
.file_release = nfs4_proc_file_release,
- .request_init = nfs4_request_init,
- .request_compatible = nfs4_request_compatible,
.lock = nfs4_proc_lock,
};
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
- if ((struct nfs4_state *)fl->fl_file->private_data != state)
+ if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
continue;
status = nfs4_lock_reclaim(state, fl);
if (status >= 0)
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->wb_list);
- init_waitqueue_head(&p->wb_wait);
}
return p;
}
* User should ensure it is safe to sleep in this function.
*/
struct nfs_page *
-nfs_create_request(struct file *file, struct inode *inode,
+nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
struct page *page,
unsigned int offset, unsigned int count)
{
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = count;
- req->wb_inode = inode;
atomic_set(&req->wb_count, 1);
- server->rpc_ops->request_init(req, file);
+ req->wb_context = get_nfs_open_context(ctx);
return req;
}
+/**
+ * nfs_unlock_request - Unlock request and wake up sleepers.
+ * @req:
+ */
+void nfs_unlock_request(struct nfs_page *req)
+{
+ if (!NFS_WBACK_BUSY(req)) {
+ printk(KERN_ERR "NFS: Invalid unlock attempted\n");
+ BUG();
+ }
+ smp_mb__before_clear_bit();
+ clear_bit(PG_BUSY, &req->wb_flags);
+ smp_mb__after_clear_bit();
+ wake_up_all(&req->wb_context->waitq);
+ nfs_release_request(req);
+}
+
/**
* nfs_clear_request - Free up all resources allocated to the request
* @req:
*
- * Release all resources associated with a write request after it
+ * Release page resources associated with a write request after it
* has completed.
*/
void nfs_clear_request(struct nfs_page *req)
{
- if (req->wb_state)
- req->wb_state = NULL;
- /* Release struct file or cached credential */
- if (req->wb_file) {
- fput(req->wb_file);
- req->wb_file = NULL;
- }
- if (req->wb_cred) {
- put_rpccred(req->wb_cred);
- req->wb_cred = NULL;
- }
if (req->wb_page) {
page_cache_release(req->wb_page);
req->wb_page = NULL;
/* Release struct file or cached credential */
nfs_clear_request(req);
+ put_nfs_open_context(req->wb_context);
nfs_page_free(req);
}
int
nfs_wait_on_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_inode;
+ struct inode *inode = req->wb_context->dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
if (!NFS_WBACK_BUSY(req))
return 0;
- return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
+ return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req));
}
/**
req = nfs_list_entry(head->next);
if (prev) {
- if (req->wb_cred != prev->wb_cred)
+ if (req->wb_context->cred != prev->wb_context->cred)
+ break;
+ if (req->wb_context->lockowner != prev->wb_context->lockowner)
+ break;
+ if (req->wb_context->state != prev->wb_context->state)
break;
if (req->wb_index != (prev->wb_index + 1))
break;
extern struct rpc_procinfo nfs_procedures[];
-static struct rpc_cred *
-nfs_cred(struct inode *inode, struct file *filp)
-{
- struct rpc_cred *cred = NULL;
-
- if (filp)
- cred = (struct rpc_cred *)filp->private_data;
- if (!cred)
- cred = NFS_I(inode)->mm_cred;
- return cred;
-}
-
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
return status;
}
-static int
-nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
+static int nfs_proc_read(struct nfs_read_data *rdata)
{
int flags = rdata->flags;
struct inode * inode = rdata->inode;
.rpc_proc = &nfs_procedures[NFSPROC_READ],
.rpc_argp = &rdata->args,
.rpc_resp = &rdata->res,
+ .rpc_cred = rdata->cred,
};
int status;
dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset);
fattr->valid = 0;
- msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
-
if (status >= 0) {
nfs_refresh_inode(inode, fattr);
/* Emulate the eof flag, which isn't normally needed in NFSv2
return status;
}
-static int
-nfs_proc_write(struct nfs_write_data *wdata, struct file *filp)
+static int nfs_proc_write(struct nfs_write_data *wdata)
{
int flags = wdata->flags;
struct inode * inode = wdata->inode;
.rpc_proc = &nfs_procedures[NFSPROC_WRITE],
.rpc_argp = &wdata->args,
.rpc_resp = &wdata->res,
+ .rpc_cred = wdata->cred,
};
int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset);
fattr->valid = 0;
- msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
if (status >= 0) {
nfs_refresh_inode(inode, fattr);
BUG();
}
-/*
- * Set up the nfspage struct with the right credentials
- */
-static void
-nfs_request_init(struct nfs_page *req, struct file *filp)
-{
- req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp));
-}
-
-static int
-nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
-{
- if (req->wb_file != filp)
- return 0;
- if (req->wb_page != page)
- return 0;
- if (req->wb_cred != nfs_file_cred(filp))
- return 0;
- return 1;
-}
-
static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
.commit_setup = nfs_proc_commit_setup,
.file_open = nfs_open,
.file_release = nfs_release,
- .request_init = nfs_request_init,
- .request_compatible = nfs_request_compatible,
.lock = nfs_proc_lock,
};
/*
* Read a page synchronously.
*/
-static int
-nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
+static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
+ struct page *page)
{
unsigned int rsize = NFS_SERVER(inode)->rsize;
unsigned int count = PAGE_CACHE_SIZE;
memset(rdata, 0, sizeof(*rdata));
rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+ rdata->cred = ctx->cred;
rdata->inode = inode;
INIT_LIST_HEAD(&rdata->pages);
rdata->args.fh = NFS_FH(inode);
- rdata->args.lockowner = current->files;
+ rdata->args.lockowner = ctx->lockowner;
+ rdata->args.state = ctx->state;
rdata->args.pages = &page;
rdata->args.pgbase = 0UL;
rdata->args.count = rsize;
rdata->args.count);
lock_kernel();
- result = NFS_PROTO(inode)->read(rdata, file);
+ result = NFS_PROTO(inode)->read(rdata);
unlock_kernel();
/*
return result;
}
-static int
-nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
+static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
+ struct page *page)
{
LIST_HEAD(one_request);
struct nfs_page *new;
len = nfs_page_length(inode, page);
if (len == 0)
return nfs_return_empty_page(page);
- new = nfs_create_request(file, inode, page, 0, len);
+ new = nfs_create_request(ctx, inode, page, 0, len);
if (IS_ERR(new)) {
unlock_page(page);
return PTR_ERR(new);
nfs_unlock_request(req);
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
- req->wb_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_inode),
+ req->wb_context->dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
}
struct inode *inode;
data->req = req;
- data->inode = inode = req->wb_inode;
- data->cred = req->wb_cred;
+ data->inode = inode = req->wb_context->dentry->d_inode;
+ data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset;
data->args.pgbase = req->wb_pgbase + offset;
data->args.pages = data->pagevec;
data->args.count = count;
- data->args.lockowner = req->wb_lockowner;
- data->args.state = req->wb_state;
+ data->args.lockowner = req->wb_context->lockowner;
+ data->args.state = req->wb_context->state;
data->res.fattr = &data->fattr;
data->res.count = count;
while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, rpages);
req = nfs_list_entry(one_request.next);
- error = nfs_pagein_one(&one_request, req->wb_inode);
+ error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
if (error < 0)
break;
}
* - The error flag is set for this page. This happens only when a
* previous async read operation failed.
*/
-int
-nfs_readpage(struct file *file, struct page *page)
+int nfs_readpage(struct file *file, struct page *page)
{
+ struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host;
int error;
if (error)
goto out_error;
+ if (file == NULL) {
+ ctx = nfs_find_open_context(inode, FMODE_READ);
+ if (ctx == NULL)
+ return -EBADF;
+ } else
+ ctx = get_nfs_open_context((struct nfs_open_context *)
+ file->private_data);
if (!IS_SYNC(inode)) {
- error = nfs_readpage_async(file, inode, page);
+ error = nfs_readpage_async(ctx, inode, page);
goto out;
}
- error = nfs_readpage_sync(file, inode, page);
+ error = nfs_readpage_sync(ctx, inode, page);
if (error < 0 && IS_SWAPFILE(inode))
printk("Aiee.. nfs swap-in of page failed!\n");
out:
+ put_nfs_open_context(ctx);
return error;
out_error:
unlock_page(page);
- goto out;
+ return error;
}
struct nfs_readdesc {
struct list_head *head;
- struct file *filp;
+ struct nfs_open_context *ctx;
};
static int
len = nfs_page_length(inode, page);
if (len == 0)
return nfs_return_empty_page(page);
- new = nfs_create_request(desc->filp, inode, page, 0, len);
+ new = nfs_create_request(desc->ctx, inode, page, 0, len);
if (IS_ERR(new)) {
SetPageError(page);
unlock_page(page);
return 0;
}
-int
-nfs_readpages(struct file *filp, struct address_space *mapping,
+int nfs_readpages(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
LIST_HEAD(head);
struct nfs_readdesc desc = {
- .filp = filp,
.head = &head,
};
struct inode *inode = mapping->host;
(long long)NFS_FILEID(inode),
nr_pages);
+ if (filp == NULL) {
+ desc.ctx = nfs_find_open_context(inode, FMODE_READ);
+ if (desc.ctx == NULL)
+ return -EBADF;
+ } else
+ desc.ctx = get_nfs_open_context((struct nfs_open_context *)
+ filp->private_data);
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
if (!list_empty(&head)) {
int err = nfs_pagein_list(&head, server->rpages);
if (!ret)
ret = err;
}
+ put_nfs_open_context(desc.ctx);
return ret;
}
/*
* Local function declarations
*/
-static struct nfs_page * nfs_update_request(struct file*, struct inode *,
+static struct nfs_page * nfs_update_request(struct nfs_open_context*,
+ struct inode *,
struct page *,
unsigned int, unsigned int);
static void nfs_writeback_done_partial(struct nfs_write_data *, int);
* Write a page synchronously.
* Offset is the data offset within the page.
*/
-static int nfs_writepage_sync(struct file *file, struct inode *inode,
+static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
struct page *page, unsigned int offset, unsigned int count,
int how)
{
memset(wdata, 0, sizeof(*wdata));
wdata->flags = how;
+ wdata->cred = ctx->cred;
wdata->inode = inode;
wdata->args.fh = NFS_FH(inode);
- wdata->args.lockowner = current->files;
+ wdata->args.lockowner = ctx->lockowner;
+ wdata->args.state = ctx->state;
wdata->args.pages = &page;
wdata->args.stable = NFS_FILE_SYNC;
wdata->args.pgbase = offset;
wdata->args.count = count;
wdata->args.offset = page_offset(page) + wdata->args.pgbase;
- result = NFS_PROTO(inode)->write(wdata, file);
+ result = NFS_PROTO(inode)->write(wdata);
if (result < 0) {
/* Must mark the page invalid after I/O error */
io_error:
nfs_end_data_update_defer(inode);
- if (wdata->cred)
- put_rpccred(wdata->cred);
kfree(wdata);
return written ? written : result;
}
-static int nfs_writepage_async(struct file *file, struct inode *inode,
- struct page *page, unsigned int offset, unsigned int count)
+static int nfs_writepage_async(struct nfs_open_context *ctx,
+ struct inode *inode, struct page *page,
+ unsigned int offset, unsigned int count)
{
struct nfs_page *req;
int status;
- req = nfs_update_request(file, inode, page, offset, count);
+ req = nfs_update_request(ctx, inode, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status < 0)
goto out;
*/
int nfs_writepage(struct page *page, struct writeback_control *wbc)
{
+ struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host;
unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE;
if (page->index >= end_index+1 || !offset)
goto out;
do_it:
+ ctx = nfs_find_open_context(inode, FMODE_WRITE);
+ if (ctx == NULL) {
+ err = -EBADF;
+ goto out;
+ }
lock_kernel();
if (!IS_SYNC(inode) && inode_referenced) {
- err = nfs_writepage_async(NULL, inode, page, 0, offset);
+ err = nfs_writepage_async(ctx, inode, page, 0, offset);
if (err >= 0) {
err = 0;
if (wbc->for_reclaim)
nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
}
} else {
- err = nfs_writepage_sync(NULL, inode, page, 0,
+ err = nfs_writepage_sync(ctx, inode, page, 0,
offset, priority);
if (err >= 0) {
if (err != offset)
}
}
unlock_kernel();
+ put_nfs_open_context(ctx);
out:
unlock_page(page);
if (inode_referenced)
/*
* Insert a write request into an inode
*/
-static void
-nfs_inode_remove_request(struct nfs_page *req)
+static void nfs_inode_remove_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_inode;
+ struct inode *inode = req->wb_context->dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
BUG_ON (!NFS_WBACK_BUSY(req));
static void
nfs_mark_request_dirty(struct nfs_page *req)
{
- struct inode *inode = req->wb_inode;
+ struct inode *inode = req->wb_context->dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfsi->req_lock);
static inline int
nfs_dirty_request(struct nfs_page *req)
{
- struct nfs_inode *nfsi = NFS_I(req->wb_inode);
+ struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
}
static void
nfs_mark_request_commit(struct nfs_page *req)
{
- struct inode *inode = req->wb_inode;
+ struct inode *inode = req->wb_context->dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfsi->req_lock);
*
* Note: Should always be called with the Page Lock held!
*/
-static struct nfs_page *
-nfs_update_request(struct file* file, struct inode *inode, struct page *page,
- unsigned int offset, unsigned int bytes)
+static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
+ struct inode *inode, struct page *page,
+ unsigned int offset, unsigned int bytes)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_inode *nfsi = NFS_I(inode);
}
spin_unlock(&nfsi->req_lock);
- new = nfs_create_request(file, inode, page, offset, bytes);
+ new = nfs_create_request(ctx, inode, page, offset, bytes);
if (IS_ERR(new))
return new;
- if (file) {
- new->wb_file = file;
- get_file(file);
- }
}
/* We have a request for our page.
* request.
*/
rqend = req->wb_offset + req->wb_bytes;
- if (req->wb_file != file
+ if (req->wb_context != ctx
|| req->wb_page != page
|| !nfs_dirty_request(req)
|| offset > rqend || end < req->wb_offset) {
return req;
}
-int
-nfs_flush_incompatible(struct file *file, struct page *page)
+int nfs_flush_incompatible(struct file *file, struct page *page)
{
+ struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
struct inode *inode = page->mapping->host;
struct nfs_page *req;
int status = 0;
*/
req = nfs_find_request(inode, page->index);
if (req) {
- if (!NFS_PROTO(inode)->request_compatible(req, file, page))
+ if (req->wb_page != page || ctx != req->wb_context)
status = nfs_wb_page(inode, page);
nfs_release_request(req);
}
int nfs_updatepage(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
+ struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
struct dentry *dentry = file->f_dentry;
struct inode *inode = page->mapping->host;
struct nfs_page *req;
count, (long long)(page_offset(page) +offset));
if (IS_SYNC(inode)) {
- status = nfs_writepage_sync(file, inode, page, offset, count, 0);
+ status = nfs_writepage_sync(ctx, inode, page, offset, count, 0);
if (status > 0) {
if (offset == 0 && status == PAGE_CACHE_SIZE)
SetPageUptodate(page);
* it out now.
*/
do {
- req = nfs_update_request(file, inode, page, offset, count);
+ req = nfs_update_request(ctx, inode, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status != -EBUSY)
break;
* NB: take care not to mess about with data->commit et al. */
data->req = req;
- data->inode = inode = req->wb_inode;
- data->cred = req->wb_cred;
+ data->inode = inode = req->wb_context->dentry->d_inode;
+ data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset;
data->args.pgbase = req->wb_pgbase + offset;
data->args.pages = data->pagevec;
data->args.count = count;
- data->args.lockowner = req->wb_lockowner;
- data->args.state = req->wb_state;
+ data->args.lockowner = req->wb_context->lockowner;
+ data->args.state = req->wb_context->state;
data->res.fattr = &data->fattr;
data->res.count = count;
while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, wpages);
req = nfs_list_entry(one_request.next);
- error = nfs_flush_one(&one_request, req->wb_inode, how);
+ error = nfs_flush_one(&one_request, req->wb_context->dentry->d_inode, how);
if (error < 0)
break;
}
struct page *page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)",
- req->wb_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_inode),
+ req->wb_context->dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
if (status < 0) {
ClearPageUptodate(page);
SetPageError(page);
- if (req->wb_file)
- req->wb_file->f_error = status;
+ req->wb_context->error = status;
dprintk(", error = %d\n", status);
} else {
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)",
- req->wb_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_inode),
+ req->wb_context->dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
if (status < 0) {
ClearPageUptodate(page);
SetPageError(page);
- if (req->wb_file)
- req->wb_file->f_error = status;
+ req->wb_context->error = status;
end_page_writeback(page);
nfs_inode_remove_request(req);
dprintk(", error = %d\n", status);
list_splice_init(head, &data->pages);
first = nfs_list_entry(data->pages.next);
last = nfs_list_entry(data->pages.prev);
- inode = first->wb_inode;
+ inode = first->wb_context->dentry->d_inode;
/*
* Determine the offset range of requests in the COMMIT call.
len = 0;
data->inode = inode;
- data->cred = first->wb_cred;
+ data->cred = first->wb_context->cred;
data->args.fh = NFS_FH(data->inode);
data->args.offset = start;
nfs_list_remove_request(req);
dprintk("NFS: commit (%s/%Ld %d@%Ld)",
- req->wb_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_inode),
+ req->wb_context->dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
if (task->tk_status < 0) {
- if (req->wb_file)
- req->wb_file->f_error = task->tk_status;
+ req->wb_context->error = task->tk_status;
nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status);
goto next;
int mask;
};
+struct nfs4_state;
+struct nfs_open_context {
+ atomic_t count;
+ struct dentry *dentry;
+ struct rpc_cred *cred;
+ struct nfs4_state *state;
+ fl_owner_t lockowner;
+ int mode;
+ int error;
+
+ struct list_head list;
+ wait_queue_head_t waitq;
+};
+
/*
* nfs fs inode data in memory
*/
ncommit,
npages;
- /* Credentials for shared mmap */
- struct rpc_cred *mm_cred;
+ /* Open contexts for shared mmap writes */
+ struct list_head open_files;
wait_queue_head_t nfs_i_wait;
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
-extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern void nfs_begin_data_update(struct inode *);
extern void nfs_end_data_update(struct inode *);
extern void nfs_end_data_update_defer(struct inode *);
+extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred);
+extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
+extern void put_nfs_open_context(struct nfs_open_context *ctx);
+extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
+extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, int mode);
+extern void nfs_file_clear_open_context(struct file *filp);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/
extern struct file_operations nfs_file_operations;
extern struct address_space_operations nfs_file_aops;
-static __inline__ struct rpc_cred *
-nfs_file_cred(struct file *file)
+static inline struct rpc_cred *nfs_file_cred(struct file *file)
{
- struct rpc_cred *cred = NULL;
- if (file)
- cred = (struct rpc_cred *)file->private_data;
-#ifdef RPC_DEBUG
- BUG_ON(cred && cred->cr_magic != RPCAUTH_CRED_MAGIC);
-#endif
- return cred;
+ if (file != NULL) {
+ struct nfs_open_context *ctx;
+
+ ctx = (struct nfs_open_context*)file->private_data;
+ return ctx->cred;
+ }
+ return NULL;
}
/*
#define destroy_nfsv4_state(server) do { } while (0)
#define nfs4_put_state_owner(inode, owner) do { } while (0)
#define nfs4_put_open_state(state) do { } while (0)
+#define nfs4_close_state(a, b) do { } while (0)
#define nfs4_renewd_prepare_shutdown(server) do { } while (0)
#endif
struct nfs_page {
struct list_head wb_list, /* Defines state of page: */
*wb_list_head; /* read/write/commit */
- struct file *wb_file;
- fl_owner_t wb_lockowner;
- struct inode *wb_inode;
- struct rpc_cred *wb_cred;
- struct nfs4_state *wb_state;
struct page *wb_page; /* page to read in/write out */
+ struct nfs_open_context *wb_context; /* File state context info */
atomic_t wb_complete; /* i/os we're waiting for */
- wait_queue_head_t wb_wait; /* wait queue */
unsigned long wb_index; /* Offset >> PAGE_CACHE_SHIFT */
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
wb_pgbase, /* Start of page data */
#define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags))
#define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
-extern struct nfs_page *nfs_create_request(struct file *, struct inode *,
- struct page *,
- unsigned int, unsigned int);
+extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
+ struct inode *inode,
+ struct page *page,
+ unsigned int offset,
+ unsigned int count);
extern void nfs_clear_request(struct nfs_page *req);
extern void nfs_release_request(struct nfs_page *req);
extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
unsigned int);
extern int nfs_wait_on_request(struct nfs_page *);
+extern void nfs_unlock_request(struct nfs_page *req);
/*
* Lock the page of an asynchronous request without incrementing the wb_count
return 1;
}
-static inline void
-nfs_unlock_request(struct nfs_page *req)
-{
- if (!NFS_WBACK_BUSY(req)) {
- printk(KERN_ERR "NFS: Invalid unlock attempted\n");
- BUG();
- }
- smp_mb__before_clear_bit();
- clear_bit(PG_BUSY, &req->wb_flags);
- smp_mb__after_clear_bit();
- wake_up_all(&req->wb_wait);
- nfs_release_request(req);
-}
/**
* nfs_list_remove_request - Remove a request from its wb_list
struct nfs_fh *, struct nfs_fattr *);
int (*access) (struct inode *, struct nfs_access_entry *);
int (*readlink)(struct inode *, struct page *);
- int (*read) (struct nfs_read_data *, struct file *);
- int (*write) (struct nfs_write_data *, struct file *);
- int (*commit) (struct nfs_write_data *, struct file *);
+ int (*read) (struct nfs_read_data *);
+ int (*write) (struct nfs_write_data *);
+ int (*commit) (struct nfs_write_data *);
struct inode * (*create) (struct inode *, struct qstr *,
struct iattr *, int);
int (*remove) (struct inode *, struct qstr *);
void (*commit_setup) (struct nfs_write_data *, int how);
int (*file_open) (struct inode *, struct file *);
int (*file_release) (struct inode *, struct file *);
- void (*request_init)(struct nfs_page *, struct file *);
- int (*request_compatible)(struct nfs_page *, struct file *, struct page *);
int (*lock)(struct file *, int, struct file_lock *);
};