Commit 477d40b4 authored by Trond Myklebust's avatar Trond Myklebust

Merge fys.uio.no:/home/linux/bitkeeper/nfsclient-2.6

into fys.uio.no:/home/linux/bitkeeper/work/nfsclient-2.6
parents fec00732 60fa4cfb
...@@ -982,12 +982,18 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, ...@@ -982,12 +982,18 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
/* We may have been initialized further down */ /* We may have been initialized further down */
if (dentry->d_inode) if (dentry->d_inode)
return 0; return 0;
if (fhandle->size == 0 || !(fattr->valid & NFS_ATTR_FATTR)) { if (fhandle->size == 0) {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error) if (error)
goto out_err; goto out_err;
} }
if (!(fattr->valid & NFS_ATTR_FATTR)) {
struct nfs_server *server = NFS_SB(dentry->d_sb);
error = server->rpc_ops->getattr(server, fhandle, fattr);
if (error < 0)
goto out_err;
}
inode = nfs_fhget(dentry->d_sb, fhandle, fattr); inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode) { if (inode) {
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
......
...@@ -110,7 +110,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty) ...@@ -110,7 +110,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
* nfs_direct_read_seg - Read in one iov segment. Generate separate * nfs_direct_read_seg - Read in one iov segment. Generate separate
* read RPCs for each "rsize" bytes. * read RPCs for each "rsize" bytes.
* @inode: target inode * @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 * user_addr: starting address of this segment of user's buffer
* count: size of this segment * count: size of this segment
* file_offset: offset in file to begin the operation * file_offset: offset in file to begin the operation
...@@ -118,7 +118,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty) ...@@ -118,7 +118,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
* nr_pages: size of pages array * nr_pages: size of pages array
*/ */
static int 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, unsigned long user_addr, size_t count, loff_t file_offset,
struct page **pages, int nr_pages) struct page **pages, int nr_pages)
{ {
...@@ -127,9 +127,10 @@ nfs_direct_read_seg(struct inode *inode, struct file *file, ...@@ -127,9 +127,10 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
int curpage = 0; int curpage = 0;
struct nfs_read_data rdata = { struct nfs_read_data rdata = {
.inode = inode, .inode = inode,
.cred = ctx->cred,
.args = { .args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.lockowner = current->files, .context = ctx,
}, },
.res = { .res = {
.fattr = &rdata.fattr, .fattr = &rdata.fattr,
...@@ -151,7 +152,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file, ...@@ -151,7 +152,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
user_addr + tot_bytes, rdata.args.pgbase, curpage); user_addr + tot_bytes, rdata.args.pgbase, curpage);
lock_kernel(); lock_kernel();
result = NFS_PROTO(inode)->read(&rdata, file); result = NFS_PROTO(inode)->read(&rdata);
unlock_kernel(); unlock_kernel();
if (result <= 0) { if (result <= 0) {
...@@ -183,7 +184,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file, ...@@ -183,7 +184,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
* nfs_direct_read - For each iov segment, map the user's buffer * nfs_direct_read - For each iov segment, map the user's buffer
* then generate read RPCs. * then generate read RPCs.
* @inode: target inode * @inode: target inode
* @file: target file (may be NULL) * @ctx: target file open context
* @iov: array of vectors that define I/O buffer * @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation * file_offset: offset in file to begin the operation
* nr_segs: size of iovec array * nr_segs: size of iovec array
...@@ -193,7 +194,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file, ...@@ -193,7 +194,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
* server. * server.
*/ */
static ssize_t 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, const struct iovec *iov, loff_t file_offset,
unsigned long nr_segs) unsigned long nr_segs)
{ {
...@@ -216,7 +217,7 @@ nfs_direct_read(struct inode *inode, struct file *file, ...@@ -216,7 +217,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
return page_count; 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); file_offset, pages, page_count);
nfs_free_user_pages(pages, page_count, 1); nfs_free_user_pages(pages, page_count, 1);
...@@ -239,7 +240,7 @@ nfs_direct_read(struct inode *inode, struct file *file, ...@@ -239,7 +240,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
* nfs_direct_write_seg - Write out one iov segment. Generate separate * nfs_direct_write_seg - Write out one iov segment. Generate separate
* write RPCs for each "wsize" bytes, then commit. * write RPCs for each "wsize" bytes, then commit.
* @inode: target inode * @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 * user_addr: starting address of this segment of user's buffer
* count: size of this segment * count: size of this segment
* file_offset: offset in file to begin the operation * file_offset: offset in file to begin the operation
...@@ -247,7 +248,7 @@ nfs_direct_read(struct inode *inode, struct file *file, ...@@ -247,7 +248,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
* nr_pages: size of pages array * nr_pages: size of pages array
*/ */
static int 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, unsigned long user_addr, size_t count, loff_t file_offset,
struct page **pages, int nr_pages) struct page **pages, int nr_pages)
{ {
...@@ -257,9 +258,10 @@ nfs_direct_write_seg(struct inode *inode, struct file *file, ...@@ -257,9 +258,10 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
struct nfs_writeverf first_verf; struct nfs_writeverf first_verf;
struct nfs_write_data wdata = { struct nfs_write_data wdata = {
.inode = inode, .inode = inode,
.cred = ctx->cred,
.args = { .args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.lockowner = current->files, .context = ctx,
}, },
.res = { .res = {
.fattr = &wdata.fattr, .fattr = &wdata.fattr,
...@@ -290,7 +292,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file, ...@@ -290,7 +292,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
user_addr + tot_bytes, wdata.args.pgbase, curpage); user_addr + tot_bytes, wdata.args.pgbase, curpage);
lock_kernel(); lock_kernel();
result = NFS_PROTO(inode)->write(&wdata, file); result = NFS_PROTO(inode)->write(&wdata);
unlock_kernel(); unlock_kernel();
if (result <= 0) { if (result <= 0) {
...@@ -325,7 +327,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file, ...@@ -325,7 +327,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
wdata.args.offset = file_offset; wdata.args.offset = file_offset;
lock_kernel(); lock_kernel();
result = NFS_PROTO(inode)->commit(&wdata, file); result = NFS_PROTO(inode)->commit(&wdata);
unlock_kernel(); unlock_kernel();
if (result < 0 || memcmp(&first_verf.verifier, if (result < 0 || memcmp(&first_verf.verifier,
...@@ -349,7 +351,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file, ...@@ -349,7 +351,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
* nfs_direct_write - For each iov segment, map the user's buffer * nfs_direct_write - For each iov segment, map the user's buffer
* then generate write and commit RPCs. * then generate write and commit RPCs.
* @inode: target inode * @inode: target inode
* @file: target file (may be NULL) * @ctx: target file open context
* @iov: array of vectors that define I/O buffer * @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation * file_offset: offset in file to begin the operation
* nr_segs: size of iovec array * nr_segs: size of iovec array
...@@ -358,8 +360,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file, ...@@ -358,8 +360,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
* that non-direct readers might access, so they will pick up these * that non-direct readers might access, so they will pick up these
* writes immediately. * writes immediately.
*/ */
static ssize_t static int nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx,
nfs_direct_write(struct inode *inode, struct file *file,
const struct iovec *iov, loff_t file_offset, const struct iovec *iov, loff_t file_offset,
unsigned long nr_segs) unsigned long nr_segs)
{ {
...@@ -382,7 +383,7 @@ nfs_direct_write(struct inode *inode, struct file *file, ...@@ -382,7 +383,7 @@ nfs_direct_write(struct inode *inode, struct file *file,
return page_count; 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); file_offset, pages, page_count);
nfs_free_user_pages(pages, page_count, 0); nfs_free_user_pages(pages, page_count, 0);
...@@ -414,6 +415,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ...@@ -414,6 +415,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
{ {
ssize_t result = -EINVAL; ssize_t result = -EINVAL;
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct nfs_open_context *ctx;
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
...@@ -423,19 +425,20 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ...@@ -423,19 +425,20 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
return result; return result;
ctx = (struct nfs_open_context *)file->private_data;
switch (rw) { switch (rw) {
case READ: case READ:
dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n", dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n",
dentry->d_name.name, file_offset, nr_segs); 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); file_offset, nr_segs);
break; break;
case WRITE: case WRITE:
dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n", dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n",
dentry->d_name.name, file_offset, nr_segs); 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); file_offset, nr_segs);
break; break;
default: default:
...@@ -471,6 +474,8 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t ...@@ -471,6 +474,8 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
ssize_t retval = -EINVAL; ssize_t retval = -EINVAL;
loff_t *ppos = &iocb->ki_pos; loff_t *ppos = &iocb->ki_pos;
struct file *file = iocb->ki_filp; 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 dentry *dentry = file->f_dentry;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -502,7 +507,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t ...@@ -502,7 +507,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
goto out; goto out;
} }
retval = nfs_direct_read(inode, file, &iov, pos, 1); retval = nfs_direct_read(inode, ctx, &iov, pos, 1);
if (retval > 0) if (retval > 0)
*ppos = pos + retval; *ppos = pos + retval;
...@@ -542,6 +547,8 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, ...@@ -542,6 +547,8 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
loff_t *ppos = &iocb->ki_pos; loff_t *ppos = &iocb->ki_pos;
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
struct file *file = iocb->ki_filp; 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 dentry *dentry = file->f_dentry;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -589,7 +596,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, ...@@ -589,7 +596,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
goto out; goto out;
} }
retval = nfs_direct_write(inode, file, &iov, pos, 1); retval = nfs_direct_write(inode, ctx, &iov, pos, 1);
if (mapping->nrpages) if (mapping->nrpages)
invalidate_inode_pages2(mapping); invalidate_inode_pages2(mapping);
if (retval > 0) if (retval > 0)
......
...@@ -113,6 +113,7 @@ nfs_file_release(struct inode *inode, struct file *filp) ...@@ -113,6 +113,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
static int static int
nfs_file_flush(struct file *file) 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; struct inode *inode = file->f_dentry->d_inode;
int status; int status;
...@@ -124,8 +125,8 @@ nfs_file_flush(struct file *file) ...@@ -124,8 +125,8 @@ nfs_file_flush(struct file *file)
/* Ensure that data+attribute caches are up to date after close() */ /* Ensure that data+attribute caches are up to date after close() */
status = nfs_wb_all(inode); status = nfs_wb_all(inode);
if (!status) { if (!status) {
status = file->f_error; status = ctx->error;
file->f_error = 0; ctx->error = 0;
if (!status) if (!status)
__nfs_revalidate_inode(NFS_SERVER(inode), inode); __nfs_revalidate_inode(NFS_SERVER(inode), inode);
} }
...@@ -197,6 +198,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -197,6 +198,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
static int static int
nfs_fsync(struct file *file, struct dentry *dentry, int datasync) 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; struct inode *inode = dentry->d_inode;
int status; int status;
...@@ -205,8 +207,8 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -205,8 +207,8 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
lock_kernel(); lock_kernel();
status = nfs_wb_all(inode); status = nfs_wb_all(inode);
if (!status) { if (!status) {
status = file->f_error; status = ctx->error;
file->f_error = 0; ctx->error = 0;
} }
unlock_kernel(); unlock_kernel();
return status; return status;
......
...@@ -121,8 +121,9 @@ nfs_delete_inode(struct inode * inode) ...@@ -121,8 +121,9 @@ nfs_delete_inode(struct inode * inode)
{ {
dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); 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)) { if (nfs_have_writebacks(inode)) {
printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
...@@ -139,10 +140,10 @@ static void ...@@ -139,10 +140,10 @@ static void
nfs_clear_inode(struct inode *inode) nfs_clear_inode(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct rpc_cred *cred = nfsi->mm_cred; struct rpc_cred *cred;
if (cred) nfs_wb_all(inode);
put_rpccred(cred); BUG_ON (!list_empty(&nfsi->open_files));
cred = nfsi->cache_access.cred; cred = nfsi->cache_access.cred;
if (cred) if (cred)
put_rpccred(cred); put_rpccred(cred);
...@@ -812,53 +813,114 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -812,53 +813,114 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
return err; 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 * Ensure that mmap has a recent RPC credential for use when writing out
* shared pages * shared pages
*/ */
void void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
nfs_set_mmcred(struct inode *inode, struct rpc_cred *cred)
{ {
struct rpc_cred **p = &NFS_I(inode)->mm_cred, struct inode *inode = filp->f_dentry->d_inode;
*oldcred = *p; struct nfs_inode *nfsi = NFS_I(inode);
*p = get_rpccred(cred); filp->private_data = get_nfs_open_context(ctx);
if (oldcred) spin_lock(&inode->i_lock);
put_rpccred(oldcred); 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 * These allocate and release file read/write context information.
* allocating and releasing RPC credentials for
* the file. I'll have to think about Tronds patch
* a bit more..
*/ */
int nfs_open(struct inode *inode, struct file *filp) int nfs_open(struct inode *inode, struct file *filp)
{ {
struct rpc_auth *auth; struct nfs_open_context *ctx;
struct rpc_cred *cred; struct rpc_cred *cred;
auth = NFS_CLIENT(inode)->cl_auth; if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
cred = rpcauth_lookupcred(auth, 0); return -ENOMEM;
filp->private_data = cred; ctx = alloc_nfs_open_context(filp->f_dentry, cred);
if ((filp->f_mode & FMODE_WRITE) != 0) { put_rpccred(cred);
nfs_set_mmcred(inode, 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); nfs_begin_data_update(inode);
}
return 0; return 0;
} }
int nfs_release(struct inode *inode, struct file *filp) int nfs_release(struct inode *inode, struct file *filp)
{ {
struct rpc_cred *cred;
lock_kernel();
if ((filp->f_mode & FMODE_WRITE) != 0) if ((filp->f_mode & FMODE_WRITE) != 0)
nfs_end_data_update(inode); nfs_end_data_update(inode);
cred = nfs_file_cred(filp); nfs_file_clear_open_context(filp);
if (cred)
put_rpccred(cred);
unlock_kernel();
return 0; return 0;
} }
...@@ -899,7 +961,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) ...@@ -899,7 +961,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
/* Protect against RPC races by saving the change attribute */ /* Protect against RPC races by saving the change attribute */
verifier = nfs_save_change_attribute(inode); verifier = nfs_save_change_attribute(inode);
status = NFS_PROTO(inode)->getattr(inode, &fattr); status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
if (status) { if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
inode->i_sb->s_id, inode->i_sb->s_id,
...@@ -1397,6 +1459,9 @@ static void nfs4_clear_inode(struct inode *inode) ...@@ -1397,6 +1459,9 @@ static void nfs4_clear_inode(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); 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)) { while (!list_empty(&nfsi->open_states)) {
struct nfs4_state *state; struct nfs4_state *state;
...@@ -1411,8 +1476,6 @@ static void nfs4_clear_inode(struct inode *inode) ...@@ -1411,8 +1476,6 @@ static void nfs4_clear_inode(struct inode *inode)
BUG_ON(atomic_read(&state->count) != 1); BUG_ON(atomic_read(&state->count) != 1);
nfs4_close_state(state, state->state); nfs4_close_state(state, state->state);
} }
/* Now call standard NFS clear_inode() code */
nfs_clear_inode(inode);
} }
...@@ -1510,8 +1573,13 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1510,8 +1573,13 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp); nfs_idmap_new(clp);
} }
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks)) {
clear_bit(NFS4CLNT_OK, &clp->cl_state); err = nfs4_init_client(clp);
if (err != 0) {
up_write(&clp->cl_sem);
goto out_fail;
}
}
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
clnt = rpc_clone_client(clp->cl_rpcclient); clnt = rpc_clone_client(clp->cl_rpcclient);
if (!IS_ERR(clnt)) if (!IS_ERR(clnt))
...@@ -1712,7 +1780,6 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) ...@@ -1712,7 +1780,6 @@ static struct inode *nfs_alloc_inode(struct super_block *sb)
if (!nfsi) if (!nfsi)
return NULL; return NULL;
nfsi->flags = 0; nfsi->flags = 0;
nfsi->mm_cred = NULL;
nfs4_zero_state(nfsi); nfs4_zero_state(nfsi);
return &nfsi->vfs_inode; return &nfsi->vfs_inode;
} }
...@@ -1732,6 +1799,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) ...@@ -1732,6 +1799,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
spin_lock_init(&nfsi->req_lock); spin_lock_init(&nfsi->req_lock);
INIT_LIST_HEAD(&nfsi->dirty); INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit); INIT_LIST_HEAD(&nfsi->commit);
INIT_LIST_HEAD(&nfsi->open_files);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0); atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0; nfsi->ndirty = 0;
......
...@@ -68,18 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_task *task) ...@@ -68,18 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_task *task)
return 1; 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. * Bare-bones access to getattr: this is for nfs_read_super.
*/ */
...@@ -104,14 +92,15 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -104,14 +92,15 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol. * One function for each procedure in the NFS protocol.
*/ */
static int static int
nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{ {
int status; int status;
dprintk("NFS call getattr\n"); dprintk("NFS call getattr\n");
fattr->valid = 0; fattr->valid = 0;
status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR, status = rpc_call(server->client, NFS3PROC_GETATTR,
NFS_FH(inode), fattr, 0); fhandle, fattr, 0);
dprintk("NFS reply getattr\n"); dprintk("NFS reply getattr\n");
return status; return status;
} }
...@@ -233,8 +222,7 @@ nfs3_proc_readlink(struct inode *inode, struct page *page) ...@@ -233,8 +222,7 @@ nfs3_proc_readlink(struct inode *inode, struct page *page)
return status; return status;
} }
static int static int nfs3_proc_read(struct nfs_read_data *rdata)
nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
{ {
int flags = rdata->flags; int flags = rdata->flags;
struct inode * inode = rdata->inode; struct inode * inode = rdata->inode;
...@@ -243,13 +231,13 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -243,13 +231,13 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
.rpc_proc = &nfs3_procedures[NFS3PROC_READ], .rpc_proc = &nfs3_procedures[NFS3PROC_READ],
.rpc_argp = &rdata->args, .rpc_argp = &rdata->args,
.rpc_resp = &rdata->res, .rpc_resp = &rdata->res,
.rpc_cred = rdata->cred,
}; };
int status; int status;
dprintk("NFS call read %d @ %Ld\n", rdata->args.count, dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset); (long long) rdata->args.offset);
fattr->valid = 0; fattr->valid = 0;
msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
if (status >= 0) if (status >= 0)
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
...@@ -257,8 +245,7 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -257,8 +245,7 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
return status; return status;
} }
static int static int nfs3_proc_write(struct nfs_write_data *wdata)
nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
{ {
int rpcflags = wdata->flags; int rpcflags = wdata->flags;
struct inode * inode = wdata->inode; struct inode * inode = wdata->inode;
...@@ -267,13 +254,13 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp) ...@@ -267,13 +254,13 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
.rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE],
.rpc_argp = &wdata->args, .rpc_argp = &wdata->args,
.rpc_resp = &wdata->res, .rpc_resp = &wdata->res,
.rpc_cred = wdata->cred,
}; };
int status; int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count, dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset); (long long) wdata->args.offset);
fattr->valid = 0; fattr->valid = 0;
msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
if (status >= 0) if (status >= 0)
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
...@@ -281,8 +268,7 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp) ...@@ -281,8 +268,7 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
return status < 0? status : wdata->res.count; return status < 0? status : wdata->res.count;
} }
static int static int nfs3_proc_commit(struct nfs_write_data *cdata)
nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
{ {
struct inode * inode = cdata->inode; struct inode * inode = cdata->inode;
struct nfs_fattr * fattr = cdata->res.fattr; struct nfs_fattr * fattr = cdata->res.fattr;
...@@ -290,13 +276,13 @@ nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp) ...@@ -290,13 +276,13 @@ nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
.rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT],
.rpc_argp = &cdata->args, .rpc_argp = &cdata->args,
.rpc_resp = &cdata->res, .rpc_resp = &cdata->res,
.rpc_cred = cdata->cred,
}; };
int status; int status;
dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, dprintk("NFS call commit %d @ %Ld\n", cdata->args.count,
(long long) cdata->args.offset); (long long) cdata->args.offset);
fattr->valid = 0; fattr->valid = 0;
msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status >= 0) if (status >= 0)
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
...@@ -840,27 +826,6 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how) ...@@ -840,27 +826,6 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
rpc_call_setup(task, &msg, 0); 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 static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{ {
...@@ -900,7 +865,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -900,7 +865,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.commit_setup = nfs3_proc_commit_setup, .commit_setup = nfs3_proc_commit_setup,
.file_open = nfs_open, .file_open = nfs_open,
.file_release = nfs_release, .file_release = nfs_release,
.request_init = nfs3_request_init,
.request_compatible = nfs3_request_compatible,
.lock = nfs3_proc_lock, .lock = nfs3_proc_lock,
}; };
...@@ -49,7 +49,8 @@ ...@@ -49,7 +49,8 @@
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
#define NFS4_POLL_RETRY_TIME (15*HZ) #define NFS4_POLL_RETRY_MIN (1*HZ)
#define NFS4_POLL_RETRY_MAX (15*HZ)
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
...@@ -189,8 +190,7 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf ...@@ -189,8 +190,7 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf
* reclaim state on the server after a reboot. * reclaim state on the server after a reboot.
* Assumes caller is holding the sp->so_sem * Assumes caller is holding the sp->so_sem
*/ */
int static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
...@@ -227,15 +227,34 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) ...@@ -227,15 +227,34 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
return status; return status;
} }
int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { };
int err;
do {
err = _nfs4_open_reclaim(sp, state);
switch (err) {
case 0:
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
return err;
}
err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
/* /*
* Returns an nfs4_state + an referenced inode * Returns an nfs4_state + an referenced inode
*/ */
struct nfs4_state * static int _nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct nfs4_state *state = NULL; struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_client *clp = server->nfs4_state;
struct inode *inode = NULL; struct inode *inode = NULL;
int status; int status;
struct nfs_fattr f_attr = { struct nfs_fattr f_attr = {
...@@ -261,11 +280,12 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -261,11 +280,12 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
.rpc_cred = cred, .rpc_cred = cred,
}; };
retry: /* Protect against reboot recovery conflicts */
down_read(&clp->cl_sem);
status = -ENOMEM; status = -ENOMEM;
if (!(sp = nfs4_get_state_owner(NFS_SERVER(dir), cred))) { if (!(sp = nfs4_get_state_owner(server, cred))) {
dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
goto out; goto out_err;
} }
if (o_arg.createmode & NFS4_CREATE_EXCLUSIVE){ if (o_arg.createmode & NFS4_CREATE_EXCLUSIVE){
u32 *p = (u32 *) o_arg.u.verifier.data; u32 *p = (u32 *) o_arg.u.verifier.data;
...@@ -283,16 +303,21 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -283,16 +303,21 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_seqid(status, sp); nfs4_increment_seqid(status, sp);
if (status) if (status)
goto out_up; goto out_err;
update_changeattr(dir, &o_res.cinfo); update_changeattr(dir, &o_res.cinfo);
if (!(f_attr.valid & NFS_ATTR_FATTR)) {
status = server->rpc_ops->getattr(server, &o_res.fh, &f_attr);
if (status < 0)
goto out_err;
}
status = -ENOMEM; status = -ENOMEM;
inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
if (!inode) if (!inode)
goto out_up; goto out_err;
state = nfs4_get_open_state(inode, sp); state = nfs4_get_open_state(inode, sp);
if (!state) if (!state)
goto out_up; goto out_err;
if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
struct nfs_open_confirmargs oc_arg = { struct nfs_open_confirmargs oc_arg = {
...@@ -311,7 +336,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -311,7 +336,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_seqid(status, sp); nfs4_increment_seqid(status, sp);
if (status) if (status)
goto out_up; goto out_err;
memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid)); memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid));
} else } else
memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
...@@ -325,44 +350,58 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -325,44 +350,58 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
up(&sp->so_sema); up(&sp->so_sema);
nfs4_put_state_owner(sp); nfs4_put_state_owner(sp);
return state; up_read(&clp->cl_sem);
*res = state;
out_up: return 0;
up(&sp->so_sema); out_err:
nfs4_put_state_owner(sp); if (sp != NULL) {
if (state) { if (state != NULL)
nfs4_put_open_state(state); nfs4_put_open_state(state);
state = NULL; up(&sp->so_sema);
nfs4_put_state_owner(sp);
} }
if (inode) { /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */
up_read(&clp->cl_sem);
if (inode != NULL)
iput(inode); iput(inode);
inode = NULL; *res = NULL;
} return status;
/* NOTE: BAD_SEQID means the server and client disagree about the
* book-keeping w.r.t. state-changing operations
* (OPEN/CLOSE/LOCK/LOCKU...)
* It is actually a sign of a bug on the client or on the server.
*
* If we receive a BAD_SEQID error in the particular case of
* doing an OPEN, we assume that nfs4_increment_seqid() will
* have unhashed the old state_owner for us, and that we can
* therefore safely retry using a new one. We should still warn
* the user though...
*/
if (status == -NFS4ERR_BAD_SEQID) {
printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n");
goto retry;
}
status = nfs4_handle_error(server, status);
if (!status)
goto retry;
BUG_ON(status < -1000 || status > 0);
out:
return ERR_PTR(status);
} }
int
nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, struct nfs4_state *nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
{
struct nfs4_exception exception = { };
struct nfs4_state *res;
int status;
do {
status = _nfs4_do_open(dir, name, flags, sattr, cred, &res);
if (status == 0)
break;
/* NOTE: BAD_SEQID means the server and client disagree about the
* book-keeping w.r.t. state-changing operations
* (OPEN/CLOSE/LOCK/LOCKU...)
* It is actually a sign of a bug on the client or on the server.
*
* If we receive a BAD_SEQID error in the particular case of
* doing an OPEN, we assume that nfs4_increment_seqid() will
* have unhashed the old state_owner for us, and that we can
* therefore safely retry using a new one. We should still warn
* the user though...
*/
if (status == -NFS4ERR_BAD_SEQID) {
printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n");
exception.retry = 1;
continue;
}
res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
status, &exception));
} while (exception.retry);
return res;
}
static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
struct nfs_fh *fhandle, struct iattr *sattr, struct nfs_fh *fhandle, struct iattr *sattr,
struct nfs4_state *state) struct nfs4_state *state)
{ {
...@@ -381,9 +420,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, ...@@ -381,9 +420,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
.rpc_argp = &arg, .rpc_argp = &arg,
.rpc_resp = &res, .rpc_resp = &res,
}; };
int status;
retry:
fattr->valid = 0; fattr->valid = 0;
if (sattr->ia_valid & ATTR_SIZE) if (sattr->ia_valid & ATTR_SIZE)
...@@ -391,13 +428,22 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, ...@@ -391,13 +428,22 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
else else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
status = rpc_call_sync(server->client, &msg, 0); return rpc_call_sync(server->client, &msg, 0);
if (status) { }
status = nfs4_handle_error(server, status);
if (!status) int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
goto retry; struct nfs_fh *fhandle, struct iattr *sattr,
} struct nfs4_state *state)
return status; {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_do_setattr(server, fattr, fhandle, sattr,
state),
&exception);
} while (exception.retry);
return err;
} }
/* /*
...@@ -411,8 +457,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, ...@@ -411,8 +457,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
* *
* NOTE: Caller must be holding the sp->so_owner semaphore! * NOTE: Caller must be holding the sp->so_owner semaphore!
*/ */
int static int _nfs4_do_close(struct inode *inode, struct nfs4_state *state)
nfs4_do_close(struct inode *inode, struct nfs4_state *state)
{ {
struct nfs4_state_owner *sp = state->owner; struct nfs4_state_owner *sp = state->owner;
int status = 0; int status = 0;
...@@ -441,8 +486,27 @@ nfs4_do_close(struct inode *inode, struct nfs4_state *state) ...@@ -441,8 +486,27 @@ nfs4_do_close(struct inode *inode, struct nfs4_state *state)
return status; return status;
} }
int int nfs4_do_close(struct inode *inode, struct nfs4_state *state)
nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) {
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { };
int err;
do {
err = _nfs4_do_close(inode, state);
switch (err) {
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
nfs4_schedule_state_recovery(server->nfs4_state);
err = 0;
default:
state->state = 0;
}
err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
static int _nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
{ {
struct nfs4_state_owner *sp = state->owner; struct nfs4_state_owner *sp = state->owner;
int status = 0; int status = 0;
...@@ -467,6 +531,26 @@ nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) ...@@ -467,6 +531,26 @@ nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
return status; return status;
} }
int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
{
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { };
int err;
do {
err = _nfs4_do_downgrade(inode, state, mode);
switch (err) {
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
nfs4_schedule_state_recovery(server->nfs4_state);
err = 0;
default:
state->state = mode;
}
err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
struct inode * struct inode *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{ {
...@@ -518,7 +602,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) ...@@ -518,7 +602,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
} }
static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{ {
struct nfs4_server_caps_res res = {}; struct nfs4_server_caps_res res = {};
struct rpc_message msg = { struct rpc_message msg = {
...@@ -542,7 +626,19 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh ...@@ -542,7 +626,19 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
return status; return status;
} }
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_server_capabilities(server, fhandle),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
struct nfs_fattr * fattr = info->fattr; struct nfs_fattr * fattr = info->fattr;
...@@ -563,6 +659,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -563,6 +659,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
return rpc_call_sync(server->client, &msg, 0); return rpc_call_sync(server->client, &msg, 0);
} }
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_lookup_root(server, fhandle, info),
&exception);
} while (exception.retry);
return err;
}
static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
...@@ -597,6 +706,8 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -597,6 +706,8 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
p = server->mnt_path; p = server->mnt_path;
for (;;) { for (;;) {
struct nfs4_exception exception = { };
while (*p == '/') while (*p == '/')
p++; p++;
if (!*p) if (!*p)
...@@ -606,9 +717,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -606,9 +717,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
p++; p++;
q.len = p - q.name; q.len = p - q.name;
fattr->valid = 0; do {
status = rpc_call_sync(server->client, &msg, 0); fattr->valid = 0;
if (!status) status = nfs4_handle_exception(server,
rpc_call_sync(server->client, &msg, 0),
&exception);
} while (exception.retry);
if (status == 0)
continue; continue;
if (status == -ENOENT) { if (status == -ENOENT) {
printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path); printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
...@@ -621,14 +736,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -621,14 +736,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
if (status == 0) if (status == 0)
status = nfs4_do_fsinfo(server, fhandle, info); status = nfs4_do_fsinfo(server, fhandle, info);
out: out:
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_getattr_arg args = { struct nfs4_getattr_arg args = {
.fh = NFS_FH(inode), .fh = fhandle,
.bitmask = server->attr_bitmask, .bitmask = server->attr_bitmask,
}; };
struct nfs4_getattr_res res = { struct nfs4_getattr_res res = {
...@@ -642,8 +756,19 @@ static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) ...@@ -642,8 +756,19 @@ static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
}; };
fattr->valid = 0; fattr->valid = 0;
return rpc_call_sync(server->client, &msg, 0);
}
return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_proc_getattr(server, fhandle, fattr),
&exception);
} while (exception.retry);
return err;
} }
/* /*
...@@ -705,7 +830,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -705,7 +830,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
return status; return status;
} }
static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
int status; int status;
...@@ -731,10 +856,22 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, ...@@ -731,10 +856,22 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
dprintk("NFS call lookup %s\n", name->name); dprintk("NFS call lookup %s\n", name->name);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
dprintk("NFS reply lookup: %d\n", status); dprintk("NFS reply lookup: %d\n", status);
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_lookup(dir, name, fhandle, fattr),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{ {
struct nfs4_accessargs args = { struct nfs4_accessargs args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
...@@ -775,7 +912,19 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) ...@@ -775,7 +912,19 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
entry->mask |= MAY_EXEC; entry->mask |= MAY_EXEC;
} }
return nfs4_map_errors(status); return status;
}
static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(inode),
_nfs4_proc_access(inode, entry),
&exception);
} while (exception.retry);
return err;
} }
/* /*
...@@ -802,7 +951,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) ...@@ -802,7 +951,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
* Both of these changes to the XDR layer would in fact be quite * Both of these changes to the XDR layer would in fact be quite
* minor, but I decided to leave them for a subsequent patch. * minor, but I decided to leave them for a subsequent patch.
*/ */
static int nfs4_proc_readlink(struct inode *inode, struct page *page) static int _nfs4_proc_readlink(struct inode *inode, struct page *page)
{ {
struct nfs4_readlink args = { struct nfs4_readlink args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
...@@ -815,11 +964,22 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page) ...@@ -815,11 +964,22 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page)
.rpc_resp = NULL, .rpc_resp = NULL,
}; };
return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
} }
static int static int nfs4_proc_readlink(struct inode *inode, struct page *page)
nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp) {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(inode),
_nfs4_proc_readlink(inode, page),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_read(struct nfs_read_data *rdata)
{ {
int flags = rdata->flags; int flags = rdata->flags;
struct inode *inode = rdata->inode; struct inode *inode = rdata->inode;
...@@ -829,6 +989,7 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -829,6 +989,7 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ],
.rpc_argp = &rdata->args, .rpc_argp = &rdata->args,
.rpc_resp = &rdata->res, .rpc_resp = &rdata->res,
.rpc_cred = rdata->cred,
}; };
unsigned long timestamp = jiffies; unsigned long timestamp = jiffies;
int status; int status;
...@@ -836,29 +997,27 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -836,29 +997,27 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
dprintk("NFS call read %d @ %Ld\n", rdata->args.count, dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset); (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; fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, flags); status = rpc_call_sync(server->client, &msg, flags);
if (!status) if (!status)
renew_lease(server, timestamp); renew_lease(server, timestamp);
dprintk("NFS reply read: %d\n", status); dprintk("NFS reply read: %d\n", status);
return nfs4_map_errors(status); return status;
} }
static int static int nfs4_proc_read(struct nfs_read_data *rdata)
nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp) {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(rdata->inode),
_nfs4_proc_read(rdata),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_write(struct nfs_write_data *wdata)
{ {
int rpcflags = wdata->flags; int rpcflags = wdata->flags;
struct inode *inode = wdata->inode; struct inode *inode = wdata->inode;
...@@ -868,33 +1027,32 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp) ...@@ -868,33 +1027,32 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE],
.rpc_argp = &wdata->args, .rpc_argp = &wdata->args,
.rpc_resp = &wdata->res, .rpc_resp = &wdata->res,
.rpc_cred = wdata->cred,
}; };
int status; int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count, dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset); (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; fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, rpcflags); status = rpc_call_sync(server->client, &msg, rpcflags);
dprintk("NFS reply write: %d\n", status); dprintk("NFS reply write: %d\n", status);
return nfs4_map_errors(status); return status;
} }
static int static int nfs4_proc_write(struct nfs_write_data *wdata)
nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp) {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(wdata->inode),
_nfs4_proc_write(wdata),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_commit(struct nfs_write_data *cdata)
{ {
struct inode *inode = cdata->inode; struct inode *inode = cdata->inode;
struct nfs_fattr *fattr = cdata->res.fattr; struct nfs_fattr *fattr = cdata->res.fattr;
...@@ -903,24 +1061,29 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp) ...@@ -903,24 +1061,29 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
.rpc_argp = &cdata->args, .rpc_argp = &cdata->args,
.rpc_resp = &cdata->res, .rpc_resp = &cdata->res,
.rpc_cred = cdata->cred,
}; };
int status; int status;
dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, dprintk("NFS call commit %d @ %Ld\n", cdata->args.count,
(long long) cdata->args.offset); (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; fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
dprintk("NFS reply commit: %d\n", status); dprintk("NFS reply commit: %d\n", status);
return nfs4_map_errors(status); return status;
}
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),
&exception);
} while (exception.retry);
return err;
} }
/* /*
...@@ -967,7 +1130,7 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, ...@@ -967,7 +1130,7 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
return inode; return inode;
} }
static int nfs4_proc_remove(struct inode *dir, struct qstr *name) static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
{ {
struct nfs4_remove_arg args = { struct nfs4_remove_arg args = {
.fh = NFS_FH(dir), .fh = NFS_FH(dir),
...@@ -984,7 +1147,19 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) ...@@ -984,7 +1147,19 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (status == 0) if (status == 0)
update_changeattr(dir, &res); update_changeattr(dir, &res);
return nfs4_map_errors(status); return status;
}
static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_remove(dir, name),
&exception);
} while (exception.retry);
return err;
} }
struct unlink_desc { struct unlink_desc {
...@@ -1025,7 +1200,7 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) ...@@ -1025,7 +1200,7 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
return 0; return 0;
} }
static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name) struct inode *new_dir, struct qstr *new_name)
{ {
struct nfs4_rename_arg arg = { struct nfs4_rename_arg arg = {
...@@ -1048,10 +1223,24 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, ...@@ -1048,10 +1223,24 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
update_changeattr(old_dir, &res.old_cinfo); update_changeattr(old_dir, &res.old_cinfo);
update_changeattr(new_dir, &res.new_cinfo); update_changeattr(new_dir, &res.new_cinfo);
} }
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(old_dir),
_nfs4_proc_rename(old_dir, old_name,
new_dir, new_name),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{ {
struct nfs4_link_arg arg = { struct nfs4_link_arg arg = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
...@@ -1070,10 +1259,22 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n ...@@ -1070,10 +1259,22 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
if (!status) if (!status)
update_changeattr(dir, &cinfo); update_changeattr(dir, &cinfo);
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(inode),
_nfs4_proc_link(inode, dir, name),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fattr *fattr)
{ {
...@@ -1106,10 +1307,25 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, ...@@ -1106,10 +1307,25 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) if (!status)
update_changeattr(dir, &res.dir_cinfo); update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_symlink(dir, name, path, sattr,
fhandle, fattr),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
struct iattr *sattr, struct nfs_fh *fhandle, struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fattr *fattr)
{ {
...@@ -1139,10 +1355,25 @@ static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, ...@@ -1139,10 +1355,25 @@ static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) if (!status)
update_changeattr(dir, &res.dir_cinfo); update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_mkdir(dir, name, sattr,
fhandle, fattr),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
u64 cookie, struct page *page, unsigned int count, int plus) u64 cookie, struct page *page, unsigned int count, int plus)
{ {
struct inode *dir = dentry->d_inode; struct inode *dir = dentry->d_inode;
...@@ -1168,10 +1399,24 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -1168,10 +1399,24 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
if (status == 0) if (status == 0)
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
unlock_kernel(); unlock_kernel();
return nfs4_map_errors(status); return status;
} }
static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
u64 cookie, struct page *page, unsigned int count, int plus)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
_nfs4_proc_readdir(dentry, cred, cookie,
page, count, plus),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name,
struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
struct nfs_fattr *fattr) struct nfs_fattr *fattr)
{ {
...@@ -1218,10 +1463,25 @@ static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, ...@@ -1218,10 +1463,25 @@ static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) if (!status)
update_changeattr(dir, &res.dir_cinfo); update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status); return status;
}
static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
struct nfs_fattr *fattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_mknod(dir, name, sattr, rdev,
fh, fattr),
&exception);
} while (exception.retry);
return err;
} }
static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsstat *fsstat) struct nfs_fsstat *fsstat)
{ {
struct nfs4_statfs_arg args = { struct nfs4_statfs_arg args = {
...@@ -1235,10 +1495,22 @@ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1235,10 +1495,22 @@ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
}; };
fsstat->fattr->valid = 0; fsstat->fattr->valid = 0;
return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); return rpc_call_sync(server->client, &msg, 0);
}
static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_proc_statfs(server, fhandle, fsstat),
&exception);
} while (exception.retry);
return err;
} }
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *fsinfo) struct nfs_fsinfo *fsinfo)
{ {
struct nfs4_fsinfo_arg args = { struct nfs4_fsinfo_arg args = {
...@@ -1251,16 +1523,29 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1251,16 +1523,29 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = fsinfo, .rpc_resp = fsinfo,
}; };
return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); return rpc_call_sync(server->client, &msg, 0);
}
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_do_fsinfo(server, fhandle, fsinfo),
&exception);
} while (exception.retry);
return err;
} }
static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{ {
fsinfo->fattr->valid = 0; fsinfo->fattr->valid = 0;
return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo)); return nfs4_do_fsinfo(server, fhandle, fsinfo);
} }
static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_pathconf *pathconf) struct nfs_pathconf *pathconf)
{ {
struct nfs4_pathconf_arg args = { struct nfs4_pathconf_arg args = {
...@@ -1280,7 +1565,21 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1280,7 +1565,21 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
} }
pathconf->fattr->valid = 0; pathconf->fattr->valid = 0;
return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); return rpc_call_sync(server->client, &msg, 0);
}
static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_pathconf *pathconf)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_proc_pathconf(server, fhandle, pathconf),
&exception);
} while (exception.retry);
return err;
} }
static void static void
...@@ -1471,8 +1770,10 @@ static int ...@@ -1471,8 +1770,10 @@ static int
nfs4_proc_file_open(struct inode *inode, struct file *filp) nfs4_proc_file_open(struct inode *inode, struct file *filp)
{ {
struct dentry *dentry = filp->f_dentry; struct dentry *dentry = filp->f_dentry;
struct nfs4_state *state; struct nfs_open_context *ctx;
struct nfs4_state *state = NULL;
struct rpc_cred *cred; struct rpc_cred *cred;
int status = -ENOMEM;
dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n", dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n",
(int)dentry->d_parent->d_name.len, (int)dentry->d_parent->d_name.len,
...@@ -1482,21 +1783,28 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp) ...@@ -1482,21 +1783,28 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp)
/* Find our open stateid */ /* Find our open stateid */
cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); 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); put_rpccred(cred);
if (state == NULL) { if (unlikely(ctx == NULL))
printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__); return -ENOMEM;
return -EIO; /* ERACE actually */ 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); nfs4_close_state(state, filp->f_mode);
if (filp->f_mode & FMODE_WRITE) { ctx->mode = filp->f_mode;
lock_kernel(); nfs_file_set_open_context(filp, ctx);
nfs_set_mmcred(inode, state->owner->so_cred); put_nfs_open_context(ctx);
if (filp->f_mode & FMODE_WRITE)
nfs_begin_data_update(inode); nfs_begin_data_update(inode);
unlock_kernel();
}
filp->private_data = state;
return 0; return 0;
no_state:
printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
put_nfs_open_context(ctx);
return status;
} }
/* /*
...@@ -1505,37 +1813,12 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp) ...@@ -1505,37 +1813,12 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp)
static int static int
nfs4_proc_file_release(struct inode *inode, struct file *filp) nfs4_proc_file_release(struct inode *inode, struct file *filp)
{ {
struct nfs4_state *state = (struct nfs4_state *)filp->private_data; if (filp->f_mode & FMODE_WRITE)
if (state)
nfs4_close_state(state, filp->f_mode);
if (filp->f_mode & FMODE_WRITE) {
lock_kernel();
nfs_end_data_update(inode); nfs_end_data_update(inode);
unlock_kernel(); nfs_file_clear_open_context(filp);
}
return 0; 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 static int
nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
{ {
...@@ -1549,11 +1832,13 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) ...@@ -1549,11 +1832,13 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL);
nfs4_schedule_state_recovery(clp); nfs4_schedule_state_recovery(clp);
if (test_bit(NFS4CLNT_OK, &clp->cl_state))
rpc_wake_up_task(task);
task->tk_status = 0; task->tk_status = 0;
return -EAGAIN; return -EAGAIN;
case -NFS4ERR_GRACE: case -NFS4ERR_GRACE:
case -NFS4ERR_DELAY: case -NFS4ERR_DELAY:
rpc_delay(task, NFS4_POLL_RETRY_TIME); rpc_delay(task, NFS4_POLL_RETRY_MAX);
task->tk_status = 0; task->tk_status = 0;
return -EAGAIN; return -EAGAIN;
case -NFS4ERR_OLD_STATEID: case -NFS4ERR_OLD_STATEID:
...@@ -1564,12 +1849,11 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) ...@@ -1564,12 +1849,11 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
return 0; return 0;
} }
int int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
{ {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
sigset_t oldset; sigset_t oldset;
int interruptible, res; int interruptible, res = 0;
might_sleep(); might_sleep();
...@@ -1577,101 +1861,85 @@ nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) ...@@ -1577,101 +1861,85 @@ nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
interruptible = TASK_UNINTERRUPTIBLE; interruptible = TASK_UNINTERRUPTIBLE;
if (clnt->cl_intr) if (clnt->cl_intr)
interruptible = TASK_INTERRUPTIBLE; interruptible = TASK_INTERRUPTIBLE;
do { prepare_to_wait(&clp->cl_waitq, &wait, interruptible);
res = 0; nfs4_schedule_state_recovery(clp);
prepare_to_wait(&clp->cl_waitq, &wait, interruptible); if (clnt->cl_intr && signalled())
nfs4_schedule_state_recovery(clp); res = -ERESTARTSYS;
if (test_bit(NFS4CLNT_OK, &clp->cl_state) && else if (!test_bit(NFS4CLNT_OK, &clp->cl_state))
!test_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state))
break;
if (clnt->cl_intr && signalled()) {
res = -ERESTARTSYS;
break;
}
schedule(); schedule();
} while(!test_bit(NFS4CLNT_OK, &clp->cl_state));
finish_wait(&clp->cl_waitq, &wait); finish_wait(&clp->cl_waitq, &wait);
rpc_clnt_sigunmask(clnt, &oldset); rpc_clnt_sigunmask(clnt, &oldset);
return res; return res;
} }
static int static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
nfs4_delay(struct rpc_clnt *clnt)
{ {
sigset_t oldset; sigset_t oldset;
int res = 0; int res = 0;
might_sleep(); might_sleep();
if (*timeout <= 0)
*timeout = NFS4_POLL_RETRY_MIN;
if (*timeout > NFS4_POLL_RETRY_MAX)
*timeout = NFS4_POLL_RETRY_MAX;
rpc_clnt_sigmask(clnt, &oldset); rpc_clnt_sigmask(clnt, &oldset);
if (clnt->cl_intr) { if (clnt->cl_intr) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(NFS4_POLL_RETRY_TIME); schedule_timeout(*timeout);
if (signalled()) if (signalled())
res = -ERESTARTSYS; res = -ERESTARTSYS;
} else { } else {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(NFS4_POLL_RETRY_TIME); schedule_timeout(*timeout);
} }
rpc_clnt_sigunmask(clnt, &oldset); rpc_clnt_sigunmask(clnt, &oldset);
*timeout <<= 1;
return res; return res;
} }
/* This is the error handling routine for processes that are allowed /* This is the error handling routine for processes that are allowed
* to sleep. * to sleep.
*/ */
int int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
nfs4_handle_error(struct nfs_server *server, int errorcode)
{ {
struct nfs4_client *clp = server->nfs4_state; struct nfs4_client *clp = server->nfs4_state;
int ret = errorcode; int ret = errorcode;
exception->retry = 0;
switch(errorcode) { switch(errorcode) {
case 0:
return 0;
case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
ret = nfs4_wait_clnt_recover(server->client, clp); ret = nfs4_wait_clnt_recover(server->client, clp);
if (ret == 0)
exception->retry = 1;
break; break;
case -NFS4ERR_GRACE: case -NFS4ERR_GRACE:
case -NFS4ERR_DELAY: case -NFS4ERR_DELAY:
ret = nfs4_delay(server->client); ret = nfs4_delay(server->client, &exception->timeout);
if (ret == 0)
exception->retry = 1;
break; break;
case -NFS4ERR_OLD_STATEID: case -NFS4ERR_OLD_STATEID:
ret = 0; if (ret == 0)
exception->retry = 1;
} }
/* We failed to handle the error */ /* We failed to handle the error */
return nfs4_map_errors(ret); return nfs4_map_errors(ret);
} }
int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port)
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)
{ {
u32 *p; static nfs4_verifier sc_verifier;
struct nfs4_setclientid setclientid; static int initialized;
struct timespec tv;
struct nfs4_setclientid setclientid = {
.sc_verifier = &sc_verifier,
.sc_prog = program,
};
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
.rpc_argp = &setclientid, .rpc_argp = &setclientid,
...@@ -1679,15 +1947,24 @@ nfs4_proc_setclientid(struct nfs4_client *clp, ...@@ -1679,15 +1947,24 @@ nfs4_proc_setclientid(struct nfs4_client *clp,
.rpc_cred = clp->cl_cred, .rpc_cred = clp->cl_cred,
}; };
tv = CURRENT_TIME; if (!initialized) {
p = (u32*)setclientid.sc_verifier.data; struct timespec boot_time;
*p++ = (u32)tv.tv_sec; u32 *p;
*p = (u32)tv.tv_nsec;
setclientid.sc_name = clp->cl_ipaddr; initialized = 1;
sprintf(setclientid.sc_netid, "tcp"); boot_time = CURRENT_TIME;
sprintf(setclientid.sc_uaddr, "%s.%d.%d", clp->cl_ipaddr, port >> 8, port & 255); p = (u32*)sc_verifier.data;
setclientid.sc_prog = htonl(program); *p++ = htonl((u32)boot_time.tv_sec);
setclientid.sc_cb_ident = 0; *p = htonl((u32)boot_time.tv_nsec);
}
setclientid.sc_name_len = scnprintf(setclientid.sc_name,
sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u",
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr));
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
sizeof(setclientid.sc_netid), "tcp");
setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
sizeof(setclientid.sc_uaddr), "%s.%d.%d",
clp->cl_ipaddr, port >> 8, port & 255);
return rpc_call_sync(clp->cl_rpcclient, &msg, 0); return rpc_call_sync(clp->cl_rpcclient, &msg, 0);
} }
...@@ -1757,8 +2034,7 @@ nfs4_lck_length(struct file_lock *request) ...@@ -1757,8 +2034,7 @@ nfs4_lck_length(struct file_lock *request)
return request->fl_end - request->fl_start + 1; return request->fl_end - request->fl_start + 1;
} }
int static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
...@@ -1782,6 +2058,7 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1782,6 +2058,7 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
struct nfs4_lock_state *lsp; struct nfs4_lock_state *lsp;
int status; int status;
down_read(&clp->cl_sem);
nlo.clientid = clp->cl_clientid; nlo.clientid = clp->cl_clientid;
down(&state->lock_sema); down(&state->lock_sema);
lsp = nfs4_find_lock_state(state, request->fl_owner); lsp = nfs4_find_lock_state(state, request->fl_owner);
...@@ -1815,14 +2092,28 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1815,14 +2092,28 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
if (lsp) if (lsp)
nfs4_put_lock_state(lsp); nfs4_put_lock_state(lsp);
up(&state->lock_sema); up(&state->lock_sema);
return nfs4_map_errors(status); up_read(&clp->cl_sem);
return status;
} }
int static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(state->inode),
_nfs4_proc_getlk(state, cmd, request),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_client *clp = server->nfs4_state;
struct nfs_lockargs arg = { struct nfs_lockargs arg = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.type = nfs4_lck_type(cmd, request), .type = nfs4_lck_type(cmd, request),
...@@ -1842,31 +2133,48 @@ nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1842,31 +2133,48 @@ nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
struct nfs_locku_opargs luargs; struct nfs_locku_opargs luargs;
int status = 0; int status = 0;
down_read(&clp->cl_sem);
down(&state->lock_sema); down(&state->lock_sema);
lsp = nfs4_find_lock_state(state, request->fl_owner); lsp = nfs4_find_lock_state(state, request->fl_owner);
if (!lsp) if (!lsp)
goto out; goto out;
luargs.seqid = lsp->ls_seqid; /* We might have lost the locks! */
memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
arg.u.locku = &luargs; luargs.seqid = lsp->ls_seqid;
status = rpc_call_sync(server->client, &msg, 0); memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
nfs4_increment_lock_seqid(status, lsp); arg.u.locku = &luargs;
status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_lock_seqid(status, lsp);
}
if (status == 0) { if (status == 0) {
memcpy(&lsp->ls_stateid, &res.u.stateid, memcpy(&lsp->ls_stateid, &res.u.stateid,
sizeof(lsp->ls_stateid)); sizeof(lsp->ls_stateid));
nfs4_notify_unlck(inode, request, lsp); nfs4_notify_unlck(state, request, lsp);
} }
nfs4_put_lock_state(lsp); nfs4_put_lock_state(lsp);
out: out:
up(&state->lock_sema); up(&state->lock_sema);
if (status == 0) if (status == 0)
posix_lock_file(request->fl_file, request); posix_lock_file(request->fl_file, request);
return nfs4_map_errors(status); up_read(&clp->cl_sem);
return status;
} }
static int static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) {
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(state->inode),
_nfs4_proc_unlck(state, cmd, request),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
...@@ -1887,23 +2195,22 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1887,23 +2195,22 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
.rpc_cred = state->owner->so_cred, .rpc_cred = state->owner->so_cred,
}; };
struct nfs_lock_opargs largs = { struct nfs_lock_opargs largs = {
.reclaim = reclaim,
.new_lock_owner = 0, .new_lock_owner = 0,
}; };
int status; int status;
down(&state->lock_sema); lsp = nfs4_get_lock_state(state, request->fl_owner);
lsp = nfs4_find_lock_state(state, request->fl_owner); if (lsp == NULL)
if (lsp == NULL) { return -ENOMEM;
if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) {
struct nfs4_state_owner *owner = state->owner; struct nfs4_state_owner *owner = state->owner;
struct nfs_open_to_lock otl = { struct nfs_open_to_lock otl = {
.lock_owner = { .lock_owner = {
.clientid = server->nfs4_state->cl_clientid, .clientid = server->nfs4_state->cl_clientid,
}, },
}; };
status = -ENOMEM;
lsp = nfs4_alloc_lock_state(state, request->fl_owner);
if (!lsp)
goto out;
otl.lock_seqid = lsp->ls_seqid; otl.lock_seqid = lsp->ls_seqid;
otl.lock_owner.id = lsp->ls_id; otl.lock_owner.id = lsp->ls_id;
memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid)); memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid));
...@@ -1932,11 +2239,28 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1932,11 +2239,28 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
/* save the returned stateid. */ /* save the returned stateid. */
if (status == 0) { if (status == 0) {
memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid));
nfs4_notify_setlk(inode, request, lsp); lsp->ls_flags |= NFS_LOCK_INITIALIZED;
if (!reclaim)
nfs4_notify_setlk(state, request, lsp);
} else if (status == -NFS4ERR_DENIED) } else if (status == -NFS4ERR_DENIED)
status = -EAGAIN; status = -EAGAIN;
nfs4_put_lock_state(lsp); nfs4_put_lock_state(lsp);
out: return status;
}
int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
{
return _nfs4_do_setlk(state, F_SETLK64, request, 1);
}
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
struct nfs4_client *clp = state->owner->so_client;
int status;
down_read(&clp->cl_sem);
down(&state->lock_sema);
status = _nfs4_do_setlk(state, cmd, request, 0);
up(&state->lock_sema); up(&state->lock_sema);
if (status == 0) { if (status == 0) {
/* Note: we always want to sleep here! */ /* Note: we always want to sleep here! */
...@@ -1944,19 +2268,34 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) ...@@ -1944,19 +2268,34 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
if (posix_lock_file_wait(request->fl_file, request) < 0) if (posix_lock_file_wait(request->fl_file, request) < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
} }
return nfs4_map_errors(status); up_read(&clp->cl_sem);
return status;
}
static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(state->inode),
_nfs4_proc_setlk(state, cmd, request),
&exception);
} while (exception.retry);
return err;
} }
static int static int
nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
{ {
struct nfs_open_context *ctx;
struct nfs4_state *state; struct nfs4_state *state;
unsigned long timeout = NFS4_LOCK_MINTIMEOUT; unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
int status; int status;
/* verify open state */ /* verify open state */
state = (struct nfs4_state *)filp->private_data; ctx = (struct nfs_open_context *)filp->private_data;
BUG_ON(!state); state = ctx->state;
if (request->fl_start < 0 || request->fl_end < 0) if (request->fl_start < 0 || request->fl_end < 0)
return -EINVAL; return -EINVAL;
...@@ -2016,8 +2355,6 @@ struct nfs_rpc_ops nfs_v4_clientops = { ...@@ -2016,8 +2355,6 @@ struct nfs_rpc_ops nfs_v4_clientops = {
.commit_setup = nfs4_proc_commit_setup, .commit_setup = nfs4_proc_commit_setup,
.file_open = nfs4_proc_file_open, .file_open = nfs4_proc_file_open,
.file_release = nfs4_proc_file_release, .file_release = nfs4_proc_file_release,
.request_init = nfs4_request_init,
.request_compatible = nfs4_request_compatible,
.lock = nfs4_proc_lock, .lock = nfs4_proc_lock,
}; };
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h> #include <linux/nfs_idmap.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -106,7 +107,7 @@ nfs4_alloc_client(struct in_addr *addr) ...@@ -106,7 +107,7 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_LIST_HEAD(&clp->cl_superblocks); INIT_LIST_HEAD(&clp->cl_superblocks);
init_waitqueue_head(&clp->cl_waitq); init_waitqueue_head(&clp->cl_waitq);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_state = 1 << NFS4CLNT_NEW; clp->cl_state = 1 << NFS4CLNT_OK;
} }
return clp; return clp;
} }
...@@ -169,6 +170,16 @@ nfs4_put_client(struct nfs4_client *clp) ...@@ -169,6 +170,16 @@ nfs4_put_client(struct nfs4_client *clp)
nfs4_free_client(clp); nfs4_free_client(clp);
} }
int nfs4_init_client(struct nfs4_client *clp)
{
int status = nfs4_proc_setclientid(clp, 0, 0);
if (status == 0)
status = nfs4_proc_setclientid_confirm(clp);
if (status == 0)
nfs4_schedule_state_renewal(clp);
return status;
}
u32 u32
nfs4_alloc_lockowner_id(struct nfs4_client *clp) nfs4_alloc_lockowner_id(struct nfs4_client *clp)
{ {
...@@ -185,7 +196,6 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) ...@@ -185,7 +196,6 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
atomic_inc(&sp->so_count); atomic_inc(&sp->so_count);
sp->so_cred = cred; sp->so_cred = cred;
list_move(&sp->so_list, &clp->cl_state_owners); list_move(&sp->so_list, &clp->cl_state_owners);
sp->so_generation = clp->cl_generation;
clp->cl_nunused--; clp->cl_nunused--;
} }
return sp; return sp;
...@@ -237,8 +247,11 @@ nfs4_unhash_state_owner(struct nfs4_state_owner *sp) ...@@ -237,8 +247,11 @@ nfs4_unhash_state_owner(struct nfs4_state_owner *sp)
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
struct nfs4_state_owner * /*
nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) * Note: must be called with clp->cl_sem held in order to prevent races
* with reboot recovery!
*/
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{ {
struct nfs4_client *clp = server->nfs4_state; struct nfs4_client *clp = server->nfs4_state;
struct nfs4_state_owner *sp, *new; struct nfs4_state_owner *sp, *new;
...@@ -254,23 +267,23 @@ nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) ...@@ -254,23 +267,23 @@ nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
new->so_client = clp; new->so_client = clp;
new->so_id = nfs4_alloc_lockowner_id(clp); new->so_id = nfs4_alloc_lockowner_id(clp);
new->so_cred = cred; new->so_cred = cred;
new->so_generation = clp->cl_generation;
sp = new; sp = new;
new = NULL; new = NULL;
} }
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
if (new) if (new)
kfree(new); kfree(new);
if (sp) { if (sp != NULL)
if (!test_bit(NFS4CLNT_OK, &clp->cl_state)) return sp;
nfs4_wait_clnt_recover(server->client, clp); put_rpccred(cred);
} else return NULL;
put_rpccred(cred);
return sp;
} }
void /*
nfs4_put_state_owner(struct nfs4_state_owner *sp) * Must be called with clp->cl_sem held in order to avoid races
* with state recovery...
*/
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{ {
struct nfs4_client *clp = sp->so_client; struct nfs4_client *clp = sp->so_client;
struct rpc_cred *cred = sp->so_cred; struct rpc_cred *cred = sp->so_cred;
...@@ -330,8 +343,6 @@ __nfs4_find_state(struct inode *inode, struct rpc_cred *cred, mode_t mode) ...@@ -330,8 +343,6 @@ __nfs4_find_state(struct inode *inode, struct rpc_cred *cred, mode_t mode)
continue; continue;
if ((state->state & mode) != mode) if ((state->state & mode) != mode)
continue; continue;
/* Add the state to the head of the inode's list */
list_move(&state->inode_states, &nfsi->open_states);
atomic_inc(&state->count); atomic_inc(&state->count);
if (mode & FMODE_READ) if (mode & FMODE_READ)
state->nreaders++; state->nreaders++;
...@@ -353,8 +364,6 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) ...@@ -353,8 +364,6 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
if (state->nreaders == 0 && state->nwriters == 0) if (state->nreaders == 0 && state->nwriters == 0)
continue; continue;
if (state->owner == owner) { if (state->owner == owner) {
/* Add the state to the head of the inode's list */
list_move(&state->inode_states, &nfsi->open_states);
atomic_inc(&state->count); atomic_inc(&state->count);
return state; return state;
} }
...@@ -411,51 +420,40 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) ...@@ -411,51 +420,40 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
return state; return state;
} }
static void /*
__nfs4_put_open_state(struct nfs4_state *state) * Beware! Caller must be holding exactly one
* reference to clp->cl_sem and owner->so_sema!
*/
void nfs4_put_open_state(struct nfs4_state *state)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs4_state_owner *owner = state->owner; struct nfs4_state_owner *owner = state->owner;
int status = 0;
if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) { if (!atomic_dec_and_lock(&state->count, &inode->i_lock))
up(&owner->so_sema);
return; return;
}
if (!list_empty(&state->inode_states)) if (!list_empty(&state->inode_states))
list_del(&state->inode_states); list_del(&state->inode_states);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
list_del(&state->open_states); list_del(&state->open_states);
if (state->state != 0) { BUG_ON (state->state != 0);
do {
status = nfs4_do_close(inode, state);
if (!status)
break;
up(&owner->so_sema);
status = nfs4_handle_error(NFS_SERVER(inode), status);
down(&owner->so_sema);
} while (!status);
}
up(&owner->so_sema);
nfs4_free_open_state(state); nfs4_free_open_state(state);
nfs4_put_state_owner(owner); nfs4_put_state_owner(owner);
} }
void /*
nfs4_put_open_state(struct nfs4_state *state) * Beware! Caller must be holding no references to clp->cl_sem!
{ * of owner->so_sema!
down(&state->owner->so_sema); */
__nfs4_put_open_state(state); void nfs4_close_state(struct nfs4_state *state, mode_t mode)
}
void
nfs4_close_state(struct nfs4_state *state, mode_t mode)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs4_state_owner *owner = state->owner; struct nfs4_state_owner *owner = state->owner;
struct nfs4_client *clp = owner->so_client;
int newstate; int newstate;
int status = 0; int status = 0;
atomic_inc(&owner->so_count);
down_read(&clp->cl_sem);
down(&owner->so_sema); down(&owner->so_sema);
/* Protect against nfs4_find_state() */ /* Protect against nfs4_find_state() */
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
...@@ -466,29 +464,24 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode) ...@@ -466,29 +464,24 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
if (state->nwriters == 0 && state->nreaders == 0) if (state->nwriters == 0 && state->nreaders == 0)
list_del_init(&state->inode_states); list_del_init(&state->inode_states);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
do { newstate = 0;
newstate = 0; if (state->state != 0) {
if (state->state == 0)
break;
if (state->nreaders) if (state->nreaders)
newstate |= FMODE_READ; newstate |= FMODE_READ;
if (state->nwriters) if (state->nwriters)
newstate |= FMODE_WRITE; newstate |= FMODE_WRITE;
if (state->state == newstate) if (state->state == newstate)
break; goto out;
if (newstate != 0) if (newstate != 0)
status = nfs4_do_downgrade(inode, state, newstate); status = nfs4_do_downgrade(inode, state, newstate);
else else
status = nfs4_do_close(inode, state); status = nfs4_do_close(inode, state);
if (!status) { }
state->state = newstate; out:
break; nfs4_put_open_state(state);
} up(&owner->so_sema);
up(&owner->so_sema); nfs4_put_state_owner(owner);
status = nfs4_handle_error(NFS_SERVER(inode), status); up_read(&clp->cl_sem);
down(&owner->so_sema);
} while (!status);
__nfs4_put_open_state(state);
} }
/* /*
...@@ -524,8 +517,7 @@ nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) ...@@ -524,8 +517,7 @@ nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
* *
* The caller must be holding state->lock_sema * The caller must be holding state->lock_sema
*/ */
struct nfs4_lock_state * static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{ {
struct nfs4_lock_state *lsp; struct nfs4_lock_state *lsp;
struct nfs4_client *clp = state->owner->so_client; struct nfs4_client *clp = state->owner->so_client;
...@@ -533,12 +525,12 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) ...@@ -533,12 +525,12 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
lsp = kmalloc(sizeof(*lsp), GFP_KERNEL); lsp = kmalloc(sizeof(*lsp), GFP_KERNEL);
if (lsp == NULL) if (lsp == NULL)
return NULL; return NULL;
lsp->ls_flags = 0;
lsp->ls_seqid = 0; /* arbitrary */ lsp->ls_seqid = 0; /* arbitrary */
lsp->ls_id = -1; lsp->ls_id = -1;
memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data));
atomic_set(&lsp->ls_count, 1); atomic_set(&lsp->ls_count, 1);
lsp->ls_owner = fl_owner; lsp->ls_owner = fl_owner;
lsp->ls_parent = state;
INIT_LIST_HEAD(&lsp->ls_locks); INIT_LIST_HEAD(&lsp->ls_locks);
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
lsp->ls_id = nfs4_alloc_lockowner_id(clp); lsp->ls_id = nfs4_alloc_lockowner_id(clp);
...@@ -546,6 +538,22 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) ...@@ -546,6 +538,22 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
return lsp; return lsp;
} }
/*
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
*
* The caller must be holding state->lock_sema and clp->cl_sem
*/
struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
{
struct nfs4_lock_state * lsp;
lsp = nfs4_find_lock_state(state, owner);
if (lsp == NULL)
lsp = nfs4_alloc_lock_state(state, owner);
return lsp;
}
/* /*
* Byte-range lock aware utility to initialize the stateid of read/write * Byte-range lock aware utility to initialize the stateid of read/write
* requests. * requests.
...@@ -567,10 +575,9 @@ nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_own ...@@ -567,10 +575,9 @@ nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_own
} }
/* /*
* Called with state->lock_sema held. * Called with state->lock_sema and clp->cl_sem held.
*/ */
void void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
{ {
if (status == NFS_OK || seqid_mutating_err(-status)) if (status == NFS_OK || seqid_mutating_err(-status))
lsp->ls_seqid++; lsp->ls_seqid++;
...@@ -597,13 +604,11 @@ nfs4_check_unlock(struct file_lock *fl, struct file_lock *request) ...@@ -597,13 +604,11 @@ nfs4_check_unlock(struct file_lock *fl, struct file_lock *request)
/* /*
* Post an initialized lock_state on the state->lock_states list. * Post an initialized lock_state on the state->lock_states list.
*/ */
void void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp)
nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp)
{ {
struct nfs4_state *state = lsp->ls_parent;
if (!list_empty(&lsp->ls_locks)) if (!list_empty(&lsp->ls_locks))
return; return;
atomic_inc(&lsp->ls_count);
write_lock(&state->state_lock); write_lock(&state->state_lock);
list_add(&lsp->ls_locks, &state->lock_states); list_add(&lsp->ls_locks, &state->lock_states);
set_bit(LK_STATE_IN_USE, &state->flags); set_bit(LK_STATE_IN_USE, &state->flags);
...@@ -620,9 +625,9 @@ nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lo ...@@ -620,9 +625,9 @@ nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lo
* *
*/ */
void void
nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp) nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp)
{ {
struct nfs4_state *state = lsp->ls_parent; struct inode *inode = state->inode;
struct file_lock *fl; struct file_lock *fl;
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
...@@ -640,6 +645,7 @@ nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lo ...@@ -640,6 +645,7 @@ nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lo
if (list_empty(&state->lock_states)) if (list_empty(&state->lock_states))
clear_bit(LK_STATE_IN_USE, &state->flags); clear_bit(LK_STATE_IN_USE, &state->flags);
write_unlock(&state->state_lock); write_unlock(&state->state_lock);
nfs4_put_lock_state(lsp);
} }
/* /*
...@@ -651,20 +657,18 @@ nfs4_put_lock_state(struct nfs4_lock_state *lsp) ...@@ -651,20 +657,18 @@ nfs4_put_lock_state(struct nfs4_lock_state *lsp)
{ {
if (!atomic_dec_and_test(&lsp->ls_count)) if (!atomic_dec_and_test(&lsp->ls_count))
return; return;
if (!list_empty(&lsp->ls_locks)) BUG_ON (!list_empty(&lsp->ls_locks));
return;
kfree(lsp); kfree(lsp);
} }
/* /*
* Called with sp->so_sema held. * Called with sp->so_sema and clp->cl_sem held.
* *
* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
* failed with a seqid incrementing error - * failed with a seqid incrementing error -
* see comments nfs_fs.h:seqid_mutating_error() * see comments nfs_fs.h:seqid_mutating_error()
*/ */
void void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
{ {
if (status == NFS_OK || seqid_mutating_err(-status)) if (status == NFS_OK || seqid_mutating_err(-status))
sp->so_seqid++; sp->so_seqid++;
...@@ -693,21 +697,14 @@ nfs4_recover_state(void *data) ...@@ -693,21 +697,14 @@ nfs4_recover_state(void *data)
init_completion(&args.complete); init_completion(&args.complete);
down_read(&clp->cl_sem);
if (test_and_set_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state))
goto out_failed;
if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0) if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0)
goto out_failed_clear; goto out_failed_clear;
wait_for_completion(&args.complete); wait_for_completion(&args.complete);
return; return;
out_failed_clear: out_failed_clear:
smp_mb__before_clear_bit(); set_bit(NFS4CLNT_OK, &clp->cl_state);
clear_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state);
smp_mb__after_clear_bit();
wake_up_all(&clp->cl_waitq); wake_up_all(&clp->cl_waitq);
rpc_wake_up(&clp->cl_rpcwaitq); rpc_wake_up(&clp->cl_rpcwaitq);
out_failed:
up_read(&clp->cl_sem);
} }
/* /*
...@@ -718,24 +715,66 @@ nfs4_schedule_state_recovery(struct nfs4_client *clp) ...@@ -718,24 +715,66 @@ nfs4_schedule_state_recovery(struct nfs4_client *clp)
{ {
if (!clp) if (!clp)
return; return;
smp_mb__before_clear_bit(); if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state))
clear_bit(NFS4CLNT_OK, &clp->cl_state); schedule_work(&clp->cl_recoverd);
smp_mb__after_clear_bit();
schedule_work(&clp->cl_recoverd);
} }
static int static int nfs4_reclaim_locks(struct nfs4_state *state)
nfs4_reclaim_open_state(struct nfs4_state_owner *sp) {
struct inode *inode = state->inode;
struct file_lock *fl;
int status = 0;
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
continue;
status = nfs4_lock_reclaim(state, fl);
if (status >= 0)
continue;
switch (status) {
default:
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
__FUNCTION__, status);
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT:
/* kill_proc(fl->fl_owner, SIGLOST, 1); */
break;
case -NFS4ERR_STALE_CLIENTID:
goto out_err;
}
}
return 0;
out_err:
return status;
}
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
{ {
struct nfs4_state *state; struct nfs4_state *state;
struct nfs4_lock_state *lock;
int status = 0; int status = 0;
list_for_each_entry(state, &sp->so_states, open_states) { list_for_each_entry(state, &sp->so_states, open_states) {
if (state->state == 0) if (state->state == 0)
continue; continue;
status = nfs4_open_reclaim(sp, state); status = nfs4_open_reclaim(sp, state);
if (status >= 0) list_for_each_entry(lock, &state->lock_states, ls_locks)
lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
if (status >= 0) {
status = nfs4_reclaim_locks(state);
if (status < 0)
goto out_err;
list_for_each_entry(lock, &state->lock_states, ls_locks) {
if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
printk("%s: Lock reclaim failed!\n",
__FUNCTION__);
}
continue; continue;
}
switch (status) { switch (status) {
default: default:
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
...@@ -762,75 +801,52 @@ nfs4_reclaim_open_state(struct nfs4_state_owner *sp) ...@@ -762,75 +801,52 @@ nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
return status; return status;
} }
static int static int reclaimer(void *ptr)
reclaimer(void *ptr)
{ {
struct reclaimer_args *args = (struct reclaimer_args *)ptr; struct reclaimer_args *args = (struct reclaimer_args *)ptr;
struct nfs4_client *clp = args->clp; struct nfs4_client *clp = args->clp;
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
int generation;
int status; int status;
daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr)); daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
allow_signal(SIGKILL); allow_signal(SIGKILL);
atomic_inc(&clp->cl_count);
complete(&args->complete); complete(&args->complete);
/* Ensure exclusive access to NFSv4 state */
lock_kernel();
down_write(&clp->cl_sem);
/* Are there any NFS mounts out there? */ /* Are there any NFS mounts out there? */
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks))
goto out; goto out;
if (!test_bit(NFS4CLNT_NEW, &clp->cl_state)) { restart_loop:
status = nfs4_proc_renew(clp); status = nfs4_proc_renew(clp);
if (status == 0) { if (status == 0)
set_bit(NFS4CLNT_OK, &clp->cl_state); goto out;
goto out; status = nfs4_init_client(clp);
}
}
status = nfs4_proc_setclientid(clp, 0, 0);
if (status)
goto out_error;
status = nfs4_proc_setclientid_confirm(clp);
if (status) if (status)
goto out_error; goto out_error;
generation = ++(clp->cl_generation); /* Note: list is protected by exclusive lock on cl->cl_sem */
clear_bit(NFS4CLNT_NEW, &clp->cl_state);
set_bit(NFS4CLNT_OK, &clp->cl_state);
up_read(&clp->cl_sem);
nfs4_schedule_state_renewal(clp);
restart_loop:
spin_lock(&clp->cl_lock);
list_for_each_entry(sp, &clp->cl_state_owners, so_list) { list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
if (sp->so_generation - generation >= 0) status = nfs4_reclaim_open_state(sp);
continue;
atomic_inc(&sp->so_count);
spin_unlock(&clp->cl_lock);
down(&sp->so_sema);
if (sp->so_generation - generation < 0) {
smp_rmb();
sp->so_generation = clp->cl_generation;
status = nfs4_reclaim_open_state(sp);
}
up(&sp->so_sema);
nfs4_put_state_owner(sp);
if (status < 0) { if (status < 0) {
if (status == -NFS4ERR_STALE_CLIENTID) if (status == -NFS4ERR_STALE_CLIENTID)
nfs4_schedule_state_recovery(clp); goto restart_loop;
goto out; goto out_error;
} }
goto restart_loop;
} }
spin_unlock(&clp->cl_lock);
out: out:
smp_mb__before_clear_bit(); set_bit(NFS4CLNT_OK, &clp->cl_state);
clear_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state); up_write(&clp->cl_sem);
smp_mb__after_clear_bit(); unlock_kernel();
wake_up_all(&clp->cl_waitq); wake_up_all(&clp->cl_waitq);
rpc_wake_up(&clp->cl_rpcwaitq); rpc_wake_up(&clp->cl_rpcwaitq);
nfs4_put_client(clp);
return 0; return 0;
out_error: out_error:
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u\n", printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
NIPQUAD(clp->cl_addr.s_addr)); NIPQUAD(clp->cl_addr.s_addr), -status);
up_read(&clp->cl_sem);
goto out; goto out;
} }
......
...@@ -404,6 +404,15 @@ struct compound_hdr { ...@@ -404,6 +404,15 @@ struct compound_hdr {
BUG_ON(!p); \ BUG_ON(!p); \
} while (0) } while (0)
static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
uint32_t *p;
p = xdr_reserve_space(xdr, 4 + len);
BUG_ON(p == NULL);
xdr_encode_opaque(p, str, len);
}
static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{ {
uint32_t *p; uint32_t *p;
...@@ -903,15 +912,15 @@ static int encode_putrootfh(struct xdr_stream *xdr) ...@@ -903,15 +912,15 @@ static int encode_putrootfh(struct xdr_stream *xdr)
return 0; return 0;
} }
static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
{ {
extern nfs4_stateid zero_stateid; extern nfs4_stateid zero_stateid;
nfs4_stateid stateid; nfs4_stateid stateid;
uint32_t *p; uint32_t *p;
RESERVE_SPACE(16); RESERVE_SPACE(16);
if (state != NULL) { if (ctx->state != NULL) {
nfs4_copy_stateid(&stateid, state, lockowner); nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
WRITEMEM(stateid.data, sizeof(stateid.data)); WRITEMEM(stateid.data, sizeof(stateid.data));
} else } else
WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
...@@ -924,7 +933,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) ...@@ -924,7 +933,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_READ); WRITE32(OP_READ);
encode_stateid(xdr, args->state, args->lockowner); encode_stateid(xdr, args->context);
RESERVE_SPACE(12); RESERVE_SPACE(12);
WRITE64(args->offset); WRITE64(args->offset);
...@@ -1047,26 +1056,18 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs * ...@@ -1047,26 +1056,18 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
{ {
uint32_t total_len;
uint32_t len1, len2, len3;
uint32_t *p; uint32_t *p;
len1 = strlen(setclientid->sc_name); RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
len2 = strlen(setclientid->sc_netid);
len3 = strlen(setclientid->sc_uaddr);
total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3);
total_len = (total_len << 2) + 24 + sizeof(setclientid->sc_verifier.data);
RESERVE_SPACE(total_len);
WRITE32(OP_SETCLIENTID); WRITE32(OP_SETCLIENTID);
WRITEMEM(setclientid->sc_verifier.data, sizeof(setclientid->sc_verifier.data)); WRITEMEM(setclientid->sc_verifier->data, sizeof(setclientid->sc_verifier->data));
WRITE32(len1);
WRITEMEM(setclientid->sc_name, len1); encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
RESERVE_SPACE(4);
WRITE32(setclientid->sc_prog); WRITE32(setclientid->sc_prog);
WRITE32(len2); encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
WRITEMEM(setclientid->sc_netid, len2); encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
WRITE32(len3); RESERVE_SPACE(4);
WRITEMEM(setclientid->sc_uaddr, len3);
WRITE32(setclientid->sc_cb_ident); WRITE32(setclientid->sc_cb_ident);
return 0; return 0;
...@@ -1091,7 +1092,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args ...@@ -1091,7 +1092,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_WRITE); WRITE32(OP_WRITE);
encode_stateid(xdr, args->state, args->lockowner); encode_stateid(xdr, args->context);
RESERVE_SPACE(16); RESERVE_SPACE(16);
WRITE64(args->offset); WRITE64(args->offset);
...@@ -1252,9 +1253,9 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n ...@@ -1252,9 +1253,9 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n
goto out; goto out;
if ((status = encode_create(&xdr, args)) != 0) if ((status = encode_create(&xdr, args)) != 0)
goto out; goto out;
if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) if ((status = encode_getfh(&xdr)) != 0)
goto out; goto out;
status = encode_getfh(&xdr); status = encode_getfattr(&xdr, args->bitmask);
out: out:
return status; return status;
} }
...@@ -1325,10 +1326,10 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena ...@@ -1325,10 +1326,10 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena
status = encode_open(&xdr, args); status = encode_open(&xdr, args);
if (status) if (status)
goto out; goto out;
status = encode_getfattr(&xdr, args->bitmask); status = encode_getfh(&xdr);
if (status) if (status)
goto out; goto out;
status = encode_getfh(&xdr); status = encode_getfattr(&xdr, args->bitmask);
out: out:
return status; return status;
} }
...@@ -3220,9 +3221,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ ...@@ -3220,9 +3221,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
goto out; goto out;
if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0) if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
goto out; goto out;
if ((status = decode_getfattr(&xdr, res->fattr, res->server)) != 0) if ((status = decode_getfh(&xdr, res->fh)) != 0)
goto out; goto out;
status = decode_getfh(&xdr, res->fh); status = decode_getfattr(&xdr, res->fattr, res->server);
if (status == NFS4ERR_DELAY)
status = 0;
out: out:
return status; return status;
} }
...@@ -3296,12 +3299,14 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ope ...@@ -3296,12 +3299,14 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ope
if (status) if (status)
goto out; goto out;
status = decode_open(&xdr, res); status = decode_open(&xdr, res);
if (status)
goto out;
status = decode_getfattr(&xdr, res->f_attr, res->server);
if (status) if (status)
goto out; goto out;
status = decode_getfh(&xdr, &res->fh); status = decode_getfh(&xdr, &res->fh);
if (status)
goto out;
status = decode_getfattr(&xdr, res->f_attr, res->server);
if (status == NFS4ERR_DELAY)
status = 0;
out: out:
return status; return status;
} }
...@@ -3347,6 +3352,8 @@ static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct ...@@ -3347,6 +3352,8 @@ static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct
if (status) if (status)
goto out; goto out;
status = decode_getfattr(&xdr, res->f_attr, res->server); status = decode_getfattr(&xdr, res->f_attr, res->server);
if (status == NFS4ERR_DELAY)
status = 0;
out: out:
return status; return status;
} }
...@@ -3371,6 +3378,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ ...@@ -3371,6 +3378,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_
if (status) if (status)
goto out; goto out;
status = decode_getfattr(&xdr, res->fattr, res->server); status = decode_getfattr(&xdr, res->fattr, res->server);
if (status == NFS4ERR_DELAY)
status = 0;
out: out:
return status; return status;
} }
......
...@@ -31,7 +31,6 @@ nfs_page_alloc(void) ...@@ -31,7 +31,6 @@ nfs_page_alloc(void)
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->wb_list); INIT_LIST_HEAD(&p->wb_list);
init_waitqueue_head(&p->wb_wait);
} }
return p; return p;
} }
...@@ -57,7 +56,7 @@ nfs_page_free(struct nfs_page *p) ...@@ -57,7 +56,7 @@ nfs_page_free(struct nfs_page *p)
* User should ensure it is safe to sleep in this function. * User should ensure it is safe to sleep in this function.
*/ */
struct nfs_page * 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, struct page *page,
unsigned int offset, unsigned int count) unsigned int offset, unsigned int count)
{ {
...@@ -89,33 +88,38 @@ nfs_create_request(struct file *file, struct inode *inode, ...@@ -89,33 +88,38 @@ nfs_create_request(struct file *file, struct inode *inode,
req->wb_offset = offset; req->wb_offset = offset;
req->wb_pgbase = offset; req->wb_pgbase = offset;
req->wb_bytes = count; req->wb_bytes = count;
req->wb_inode = inode;
atomic_set(&req->wb_count, 1); atomic_set(&req->wb_count, 1);
server->rpc_ops->request_init(req, file); req->wb_context = get_nfs_open_context(ctx);
return req; 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 * nfs_clear_request - Free up all resources allocated to the request
* @req: * @req:
* *
* Release all resources associated with a write request after it * Release page resources associated with a write request after it
* has completed. * has completed.
*/ */
void nfs_clear_request(struct nfs_page *req) 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) { if (req->wb_page) {
page_cache_release(req->wb_page); page_cache_release(req->wb_page);
req->wb_page = NULL; req->wb_page = NULL;
...@@ -142,6 +146,7 @@ nfs_release_request(struct nfs_page *req) ...@@ -142,6 +146,7 @@ nfs_release_request(struct nfs_page *req)
/* Release struct file or cached credential */ /* Release struct file or cached credential */
nfs_clear_request(req); nfs_clear_request(req);
put_nfs_open_context(req->wb_context);
nfs_page_free(req); nfs_page_free(req);
} }
...@@ -185,12 +190,12 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) ...@@ -185,12 +190,12 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head)
int int
nfs_wait_on_request(struct nfs_page *req) 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); struct rpc_clnt *clnt = NFS_CLIENT(inode);
if (!NFS_WBACK_BUSY(req)) if (!NFS_WBACK_BUSY(req))
return 0; 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));
} }
/** /**
...@@ -215,7 +220,11 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, ...@@ -215,7 +220,11 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
req = nfs_list_entry(head->next); req = nfs_list_entry(head->next);
if (prev) { 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; break;
if (req->wb_index != (prev->wb_index + 1)) if (req->wb_index != (prev->wb_index + 1))
break; break;
......
...@@ -49,18 +49,6 @@ ...@@ -49,18 +49,6 @@
extern struct rpc_procinfo nfs_procedures[]; 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. * Bare-bones access to getattr: this is for nfs_read_super.
*/ */
...@@ -99,14 +87,15 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -99,14 +87,15 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol. * One function for each procedure in the NFS protocol.
*/ */
static int static int
nfs_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{ {
int status; int status;
dprintk("NFS call getattr\n"); dprintk("NFS call getattr\n");
fattr->valid = 0; fattr->valid = 0;
status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR, status = rpc_call(server->client, NFSPROC_GETATTR,
NFS_FH(inode), fattr, 0); fhandle, fattr, 0);
dprintk("NFS reply getattr\n"); dprintk("NFS reply getattr\n");
return status; return status;
} }
...@@ -167,8 +156,7 @@ nfs_proc_readlink(struct inode *inode, struct page *page) ...@@ -167,8 +156,7 @@ nfs_proc_readlink(struct inode *inode, struct page *page)
return status; return status;
} }
static int static int nfs_proc_read(struct nfs_read_data *rdata)
nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
{ {
int flags = rdata->flags; int flags = rdata->flags;
struct inode * inode = rdata->inode; struct inode * inode = rdata->inode;
...@@ -177,15 +165,14 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -177,15 +165,14 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
.rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_proc = &nfs_procedures[NFSPROC_READ],
.rpc_argp = &rdata->args, .rpc_argp = &rdata->args,
.rpc_resp = &rdata->res, .rpc_resp = &rdata->res,
.rpc_cred = rdata->cred,
}; };
int status; int status;
dprintk("NFS call read %d @ %Ld\n", rdata->args.count, dprintk("NFS call read %d @ %Ld\n", rdata->args.count,
(long long) rdata->args.offset); (long long) rdata->args.offset);
fattr->valid = 0; fattr->valid = 0;
msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
if (status >= 0) { if (status >= 0) {
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
/* Emulate the eof flag, which isn't normally needed in NFSv2 /* Emulate the eof flag, which isn't normally needed in NFSv2
...@@ -198,8 +185,7 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp) ...@@ -198,8 +185,7 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
return status; return status;
} }
static int static int nfs_proc_write(struct nfs_write_data *wdata)
nfs_proc_write(struct nfs_write_data *wdata, struct file *filp)
{ {
int flags = wdata->flags; int flags = wdata->flags;
struct inode * inode = wdata->inode; struct inode * inode = wdata->inode;
...@@ -208,13 +194,13 @@ nfs_proc_write(struct nfs_write_data *wdata, struct file *filp) ...@@ -208,13 +194,13 @@ nfs_proc_write(struct nfs_write_data *wdata, struct file *filp)
.rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_proc = &nfs_procedures[NFSPROC_WRITE],
.rpc_argp = &wdata->args, .rpc_argp = &wdata->args,
.rpc_resp = &wdata->res, .rpc_resp = &wdata->res,
.rpc_cred = wdata->cred,
}; };
int status; int status;
dprintk("NFS call write %d @ %Ld\n", wdata->args.count, dprintk("NFS call write %d @ %Ld\n", wdata->args.count,
(long long) wdata->args.offset); (long long) wdata->args.offset);
fattr->valid = 0; fattr->valid = 0;
msg.rpc_cred = nfs_cred(inode, filp);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
if (status >= 0) { if (status >= 0) {
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
...@@ -621,27 +607,6 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how) ...@@ -621,27 +607,6 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how)
BUG(); 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 static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{ {
...@@ -682,7 +647,5 @@ struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -682,7 +647,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.commit_setup = nfs_proc_commit_setup, .commit_setup = nfs_proc_commit_setup,
.file_open = nfs_open, .file_open = nfs_open,
.file_release = nfs_release, .file_release = nfs_release,
.request_init = nfs_request_init,
.request_compatible = nfs_request_compatible,
.lock = nfs_proc_lock, .lock = nfs_proc_lock,
}; };
...@@ -91,8 +91,8 @@ int nfs_return_empty_page(struct page *page) ...@@ -91,8 +91,8 @@ int nfs_return_empty_page(struct page *page)
/* /*
* Read a page synchronously. * Read a page synchronously.
*/ */
static int static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) struct page *page)
{ {
unsigned int rsize = NFS_SERVER(inode)->rsize; unsigned int rsize = NFS_SERVER(inode)->rsize;
unsigned int count = PAGE_CACHE_SIZE; unsigned int count = PAGE_CACHE_SIZE;
...@@ -105,10 +105,11 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) ...@@ -105,10 +105,11 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
memset(rdata, 0, sizeof(*rdata)); memset(rdata, 0, sizeof(*rdata));
rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
rdata->cred = ctx->cred;
rdata->inode = inode; rdata->inode = inode;
INIT_LIST_HEAD(&rdata->pages); INIT_LIST_HEAD(&rdata->pages);
rdata->args.fh = NFS_FH(inode); rdata->args.fh = NFS_FH(inode);
rdata->args.lockowner = current->files; rdata->args.context = ctx;
rdata->args.pages = &page; rdata->args.pages = &page;
rdata->args.pgbase = 0UL; rdata->args.pgbase = 0UL;
rdata->args.count = rsize; rdata->args.count = rsize;
...@@ -134,7 +135,7 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) ...@@ -134,7 +135,7 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
rdata->args.count); rdata->args.count);
lock_kernel(); lock_kernel();
result = NFS_PROTO(inode)->read(rdata, file); result = NFS_PROTO(inode)->read(rdata);
unlock_kernel(); unlock_kernel();
/* /*
...@@ -169,8 +170,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) ...@@ -169,8 +170,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
return result; return result;
} }
static int static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) struct page *page)
{ {
LIST_HEAD(one_request); LIST_HEAD(one_request);
struct nfs_page *new; struct nfs_page *new;
...@@ -179,7 +180,7 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) ...@@ -179,7 +180,7 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
len = nfs_page_length(inode, page); len = nfs_page_length(inode, page);
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); 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)) { if (IS_ERR(new)) {
unlock_page(page); unlock_page(page);
return PTR_ERR(new); return PTR_ERR(new);
...@@ -202,8 +203,8 @@ static void nfs_readpage_release(struct nfs_page *req) ...@@ -202,8 +203,8 @@ static void nfs_readpage_release(struct nfs_page *req)
nfs_unlock_request(req); nfs_unlock_request(req);
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
req->wb_inode->i_sb->s_id, req->wb_context->dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_inode), (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes, req->wb_bytes,
(long long)req_offset(req)); (long long)req_offset(req));
} }
...@@ -217,16 +218,15 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, ...@@ -217,16 +218,15 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
struct inode *inode; struct inode *inode;
data->req = req; data->req = req;
data->inode = inode = req->wb_inode; data->inode = inode = req->wb_context->dentry->d_inode;
data->cred = req->wb_cred; data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset; data->args.offset = req_offset(req) + offset;
data->args.pgbase = req->wb_pgbase + offset; data->args.pgbase = req->wb_pgbase + offset;
data->args.pages = data->pagevec; data->args.pages = data->pagevec;
data->args.count = count; data->args.count = count;
data->args.lockowner = req->wb_lockowner; data->args.context = req->wb_context;
data->args.state = req->wb_state;
data->res.fattr = &data->fattr; data->res.fattr = &data->fattr;
data->res.count = count; data->res.count = count;
...@@ -396,7 +396,7 @@ nfs_pagein_list(struct list_head *head, int rpages) ...@@ -396,7 +396,7 @@ nfs_pagein_list(struct list_head *head, int rpages)
while (!list_empty(head)) { while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, rpages); pages += nfs_coalesce_requests(head, &one_request, rpages);
req = nfs_list_entry(one_request.next); 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) if (error < 0)
break; break;
} }
...@@ -500,9 +500,9 @@ void nfs_readpage_result(struct rpc_task *task) ...@@ -500,9 +500,9 @@ void nfs_readpage_result(struct rpc_task *task)
* - The error flag is set for this page. This happens only when a * - The error flag is set for this page. This happens only when a
* previous async read operation failed. * previous async read operation failed.
*/ */
int int nfs_readpage(struct file *file, struct page *page)
nfs_readpage(struct file *file, struct page *page)
{ {
struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
int error; int error;
...@@ -519,25 +519,33 @@ nfs_readpage(struct file *file, struct page *page) ...@@ -519,25 +519,33 @@ nfs_readpage(struct file *file, struct page *page)
if (error) if (error)
goto out_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)) { if (!IS_SYNC(inode)) {
error = nfs_readpage_async(file, inode, page); error = nfs_readpage_async(ctx, inode, page);
goto out; goto out;
} }
error = nfs_readpage_sync(file, inode, page); error = nfs_readpage_sync(ctx, inode, page);
if (error < 0 && IS_SWAPFILE(inode)) if (error < 0 && IS_SWAPFILE(inode))
printk("Aiee.. nfs swap-in of page failed!\n"); printk("Aiee.. nfs swap-in of page failed!\n");
out: out:
put_nfs_open_context(ctx);
return error; return error;
out_error: out_error:
unlock_page(page); unlock_page(page);
goto out; return error;
} }
struct nfs_readdesc { struct nfs_readdesc {
struct list_head *head; struct list_head *head;
struct file *filp; struct nfs_open_context *ctx;
}; };
static int static int
...@@ -552,7 +560,7 @@ readpage_async_filler(void *data, struct page *page) ...@@ -552,7 +560,7 @@ readpage_async_filler(void *data, struct page *page)
len = nfs_page_length(inode, page); len = nfs_page_length(inode, page);
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); 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)) { if (IS_ERR(new)) {
SetPageError(page); SetPageError(page);
unlock_page(page); unlock_page(page);
...@@ -565,13 +573,11 @@ readpage_async_filler(void *data, struct page *page) ...@@ -565,13 +573,11 @@ readpage_async_filler(void *data, struct page *page)
return 0; return 0;
} }
int int nfs_readpages(struct file *filp, struct address_space *mapping,
nfs_readpages(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages) struct list_head *pages, unsigned nr_pages)
{ {
LIST_HEAD(head); LIST_HEAD(head);
struct nfs_readdesc desc = { struct nfs_readdesc desc = {
.filp = filp,
.head = &head, .head = &head,
}; };
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -583,12 +589,20 @@ nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -583,12 +589,20 @@ nfs_readpages(struct file *filp, struct address_space *mapping,
(long long)NFS_FILEID(inode), (long long)NFS_FILEID(inode),
nr_pages); 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); ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
if (!list_empty(&head)) { if (!list_empty(&head)) {
int err = nfs_pagein_list(&head, server->rpages); int err = nfs_pagein_list(&head, server->rpages);
if (!ret) if (!ret)
ret = err; ret = err;
} }
put_nfs_open_context(desc.ctx);
return ret; return ret;
} }
......
...@@ -71,7 +71,8 @@ ...@@ -71,7 +71,8 @@
/* /*
* Local function declarations * 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 *, struct page *,
unsigned int, unsigned int); unsigned int, unsigned int);
static void nfs_writeback_done_partial(struct nfs_write_data *, int); static void nfs_writeback_done_partial(struct nfs_write_data *, int);
...@@ -173,7 +174,7 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int ...@@ -173,7 +174,7 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
* Write a page synchronously. * Write a page synchronously.
* Offset is the data offset within the page. * 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, struct page *page, unsigned int offset, unsigned int count,
int how) int how)
{ {
...@@ -187,9 +188,10 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode, ...@@ -187,9 +188,10 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
memset(wdata, 0, sizeof(*wdata)); memset(wdata, 0, sizeof(*wdata));
wdata->flags = how; wdata->flags = how;
wdata->cred = ctx->cred;
wdata->inode = inode; wdata->inode = inode;
wdata->args.fh = NFS_FH(inode); wdata->args.fh = NFS_FH(inode);
wdata->args.lockowner = current->files; wdata->args.context = ctx;
wdata->args.pages = &page; wdata->args.pages = &page;
wdata->args.stable = NFS_FILE_SYNC; wdata->args.stable = NFS_FILE_SYNC;
wdata->args.pgbase = offset; wdata->args.pgbase = offset;
...@@ -208,7 +210,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode, ...@@ -208,7 +210,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
wdata->args.count = count; wdata->args.count = count;
wdata->args.offset = page_offset(page) + wdata->args.pgbase; 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) { if (result < 0) {
/* Must mark the page invalid after I/O error */ /* Must mark the page invalid after I/O error */
...@@ -234,20 +236,19 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode, ...@@ -234,20 +236,19 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
io_error: io_error:
nfs_end_data_update_defer(inode); nfs_end_data_update_defer(inode);
if (wdata->cred)
put_rpccred(wdata->cred);
kfree(wdata); kfree(wdata);
return written ? written : result; return written ? written : result;
} }
static int nfs_writepage_async(struct file *file, struct inode *inode, static int nfs_writepage_async(struct nfs_open_context *ctx,
struct page *page, unsigned int offset, unsigned int count) struct inode *inode, struct page *page,
unsigned int offset, unsigned int count)
{ {
struct nfs_page *req; struct nfs_page *req;
int status; 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; status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status < 0) if (status < 0)
goto out; goto out;
...@@ -274,6 +275,7 @@ static int wb_priority(struct writeback_control *wbc) ...@@ -274,6 +275,7 @@ static int wb_priority(struct writeback_control *wbc)
*/ */
int nfs_writepage(struct page *page, struct writeback_control *wbc) int nfs_writepage(struct page *page, struct writeback_control *wbc)
{ {
struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
unsigned long end_index; unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE; unsigned offset = PAGE_CACHE_SIZE;
...@@ -308,16 +310,21 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -308,16 +310,21 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
if (page->index >= end_index+1 || !offset) if (page->index >= end_index+1 || !offset)
goto out; goto out;
do_it: do_it:
ctx = nfs_find_open_context(inode, FMODE_WRITE);
if (ctx == NULL) {
err = -EBADF;
goto out;
}
lock_kernel(); lock_kernel();
if (!IS_SYNC(inode) && inode_referenced) { 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) { if (err >= 0) {
err = 0; err = 0;
if (wbc->for_reclaim) if (wbc->for_reclaim)
nfs_flush_inode(inode, 0, 0, FLUSH_STABLE); nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
} }
} else { } else {
err = nfs_writepage_sync(NULL, inode, page, 0, err = nfs_writepage_sync(ctx, inode, page, 0,
offset, priority); offset, priority);
if (err >= 0) { if (err >= 0) {
if (err != offset) if (err != offset)
...@@ -326,6 +333,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -326,6 +333,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
} }
} }
unlock_kernel(); unlock_kernel();
put_nfs_open_context(ctx);
out: out:
unlock_page(page); unlock_page(page);
if (inode_referenced) if (inode_referenced)
...@@ -396,10 +404,9 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req) ...@@ -396,10 +404,9 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
/* /*
* Insert a write request into an inode * Insert a write request into an inode
*/ */
static void static void nfs_inode_remove_request(struct nfs_page *req)
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); struct nfs_inode *nfsi = NFS_I(inode);
BUG_ON (!NFS_WBACK_BUSY(req)); BUG_ON (!NFS_WBACK_BUSY(req));
...@@ -450,7 +457,7 @@ nfs_find_request(struct inode *inode, unsigned long index) ...@@ -450,7 +457,7 @@ nfs_find_request(struct inode *inode, unsigned long index)
static void static void
nfs_mark_request_dirty(struct nfs_page *req) 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); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfsi->req_lock); spin_lock(&nfsi->req_lock);
...@@ -467,7 +474,7 @@ nfs_mark_request_dirty(struct nfs_page *req) ...@@ -467,7 +474,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
static inline int static inline int
nfs_dirty_request(struct nfs_page *req) 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; return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
} }
...@@ -478,7 +485,7 @@ nfs_dirty_request(struct nfs_page *req) ...@@ -478,7 +485,7 @@ nfs_dirty_request(struct nfs_page *req)
static void static void
nfs_mark_request_commit(struct nfs_page *req) 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); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfsi->req_lock); spin_lock(&nfsi->req_lock);
...@@ -619,9 +626,9 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) ...@@ -619,9 +626,9 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr)
* *
* Note: Should always be called with the Page Lock held! * Note: Should always be called with the Page Lock held!
*/ */
static struct nfs_page * static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
nfs_update_request(struct file* file, struct inode *inode, struct page *page, struct inode *inode, struct page *page,
unsigned int offset, unsigned int bytes) unsigned int offset, unsigned int bytes)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
...@@ -669,13 +676,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page, ...@@ -669,13 +676,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
} }
spin_unlock(&nfsi->req_lock); 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)) if (IS_ERR(new))
return new; return new;
if (file) {
new->wb_file = file;
get_file(file);
}
} }
/* We have a request for our page. /* We have a request for our page.
...@@ -685,7 +688,7 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page, ...@@ -685,7 +688,7 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
* request. * request.
*/ */
rqend = req->wb_offset + req->wb_bytes; rqend = req->wb_offset + req->wb_bytes;
if (req->wb_file != file if (req->wb_context != ctx
|| req->wb_page != page || req->wb_page != page
|| !nfs_dirty_request(req) || !nfs_dirty_request(req)
|| offset > rqend || end < req->wb_offset) { || offset > rqend || end < req->wb_offset) {
...@@ -706,9 +709,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page, ...@@ -706,9 +709,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
return req; return req;
} }
int int nfs_flush_incompatible(struct file *file, struct page *page)
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 inode *inode = page->mapping->host;
struct nfs_page *req; struct nfs_page *req;
int status = 0; int status = 0;
...@@ -722,7 +725,7 @@ nfs_flush_incompatible(struct file *file, struct page *page) ...@@ -722,7 +725,7 @@ nfs_flush_incompatible(struct file *file, struct page *page)
*/ */
req = nfs_find_request(inode, page->index); req = nfs_find_request(inode, page->index);
if (req) { 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); status = nfs_wb_page(inode, page);
nfs_release_request(req); nfs_release_request(req);
} }
...@@ -738,6 +741,7 @@ nfs_flush_incompatible(struct file *file, struct page *page) ...@@ -738,6 +741,7 @@ nfs_flush_incompatible(struct file *file, struct page *page)
int nfs_updatepage(struct file *file, struct page *page, int nfs_updatepage(struct file *file, struct page *page,
unsigned int offset, unsigned int count) 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 dentry *dentry = file->f_dentry;
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct nfs_page *req; struct nfs_page *req;
...@@ -748,7 +752,7 @@ int nfs_updatepage(struct file *file, struct page *page, ...@@ -748,7 +752,7 @@ int nfs_updatepage(struct file *file, struct page *page,
count, (long long)(page_offset(page) +offset)); count, (long long)(page_offset(page) +offset));
if (IS_SYNC(inode)) { 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 (status > 0) {
if (offset == 0 && status == PAGE_CACHE_SIZE) if (offset == 0 && status == PAGE_CACHE_SIZE)
SetPageUptodate(page); SetPageUptodate(page);
...@@ -785,7 +789,7 @@ int nfs_updatepage(struct file *file, struct page *page, ...@@ -785,7 +789,7 @@ int nfs_updatepage(struct file *file, struct page *page,
* it out now. * it out now.
*/ */
do { 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; status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status != -EBUSY) if (status != -EBUSY)
break; break;
...@@ -861,16 +865,15 @@ static void nfs_write_rpcsetup(struct nfs_page *req, ...@@ -861,16 +865,15 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
* NB: take care not to mess about with data->commit et al. */ * NB: take care not to mess about with data->commit et al. */
data->req = req; data->req = req;
data->inode = inode = req->wb_inode; data->inode = inode = req->wb_context->dentry->d_inode;
data->cred = req->wb_cred; data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset; data->args.offset = req_offset(req) + offset;
data->args.pgbase = req->wb_pgbase + offset; data->args.pgbase = req->wb_pgbase + offset;
data->args.pages = data->pagevec; data->args.pages = data->pagevec;
data->args.count = count; data->args.count = count;
data->args.lockowner = req->wb_lockowner; data->args.context = req->wb_context;
data->args.state = req->wb_state;
data->res.fattr = &data->fattr; data->res.fattr = &data->fattr;
data->res.count = count; data->res.count = count;
...@@ -1030,7 +1033,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) ...@@ -1030,7 +1033,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how)
while (!list_empty(head)) { while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, wpages); pages += nfs_coalesce_requests(head, &one_request, wpages);
req = nfs_list_entry(one_request.next); 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) if (error < 0)
break; break;
} }
...@@ -1055,16 +1058,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) ...@@ -1055,16 +1058,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status)
struct page *page = req->wb_page; struct page *page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)", dprintk("NFS: write (%s/%Ld %d@%Ld)",
req->wb_inode->i_sb->s_id, req->wb_context->dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_inode), (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes, req->wb_bytes,
(long long)req_offset(req)); (long long)req_offset(req));
if (status < 0) { if (status < 0) {
ClearPageUptodate(page); ClearPageUptodate(page);
SetPageError(page); SetPageError(page);
if (req->wb_file) req->wb_context->error = status;
req->wb_file->f_error = status;
dprintk(", error = %d\n", status); dprintk(", error = %d\n", status);
} else { } else {
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
...@@ -1105,16 +1107,15 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) ...@@ -1105,16 +1107,15 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
page = req->wb_page; page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)", dprintk("NFS: write (%s/%Ld %d@%Ld)",
req->wb_inode->i_sb->s_id, req->wb_context->dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_inode), (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes, req->wb_bytes,
(long long)req_offset(req)); (long long)req_offset(req));
if (status < 0) { if (status < 0) {
ClearPageUptodate(page); ClearPageUptodate(page);
SetPageError(page); SetPageError(page);
if (req->wb_file) req->wb_context->error = status;
req->wb_file->f_error = status;
end_page_writeback(page); end_page_writeback(page);
nfs_inode_remove_request(req); nfs_inode_remove_request(req);
dprintk(", error = %d\n", status); dprintk(", error = %d\n", status);
...@@ -1233,7 +1234,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, ...@@ -1233,7 +1234,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
list_splice_init(head, &data->pages); list_splice_init(head, &data->pages);
first = nfs_list_entry(data->pages.next); first = nfs_list_entry(data->pages.next);
last = nfs_list_entry(data->pages.prev); 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. * Determine the offset range of requests in the COMMIT call.
...@@ -1247,7 +1248,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, ...@@ -1247,7 +1248,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
len = 0; len = 0;
data->inode = inode; data->inode = inode;
data->cred = first->wb_cred; data->cred = first->wb_context->cred;
data->args.fh = NFS_FH(data->inode); data->args.fh = NFS_FH(data->inode);
data->args.offset = start; data->args.offset = start;
...@@ -1314,13 +1315,12 @@ nfs_commit_done(struct rpc_task *task) ...@@ -1314,13 +1315,12 @@ nfs_commit_done(struct rpc_task *task)
nfs_list_remove_request(req); nfs_list_remove_request(req);
dprintk("NFS: commit (%s/%Ld %d@%Ld)", dprintk("NFS: commit (%s/%Ld %d@%Ld)",
req->wb_inode->i_sb->s_id, req->wb_context->dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_inode), (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes, req->wb_bytes,
(long long)req_offset(req)); (long long)req_offset(req));
if (task->tk_status < 0) { if (task->tk_status < 0) {
if (req->wb_file) req->wb_context->error = task->tk_status;
req->wb_file->f_error = task->tk_status;
nfs_inode_remove_request(req); nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status); dprintk(", error = %d\n", task->tk_status);
goto next; goto next;
......
...@@ -83,6 +83,20 @@ struct nfs_access_entry { ...@@ -83,6 +83,20 @@ struct nfs_access_entry {
int mask; 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 * nfs fs inode data in memory
*/ */
...@@ -156,8 +170,8 @@ struct nfs_inode { ...@@ -156,8 +170,8 @@ struct nfs_inode {
ncommit, ncommit,
npages; npages;
/* Credentials for shared mmap */ /* Open contexts for shared mmap writes */
struct rpc_cred *mm_cred; struct list_head open_files;
wait_queue_head_t nfs_i_wait; wait_queue_head_t nfs_i_wait;
...@@ -268,7 +282,6 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, ...@@ -268,7 +282,6 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *); 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_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
...@@ -278,6 +291,12 @@ extern void nfs_end_attr_update(struct inode *); ...@@ -278,6 +291,12 @@ extern void nfs_end_attr_update(struct inode *);
extern void nfs_begin_data_update(struct inode *); extern void nfs_begin_data_update(struct inode *);
extern void nfs_end_data_update(struct inode *); extern void nfs_end_data_update(struct inode *);
extern void nfs_end_data_update_defer(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. */ /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/ extern u32 root_nfs_parse_addr(char *name); /*__init*/
...@@ -289,16 +308,15 @@ extern struct inode_operations nfs_file_inode_operations; ...@@ -289,16 +308,15 @@ extern struct inode_operations nfs_file_inode_operations;
extern struct file_operations nfs_file_operations; extern struct file_operations nfs_file_operations;
extern struct address_space_operations nfs_file_aops; extern struct address_space_operations nfs_file_aops;
static __inline__ struct rpc_cred * static inline struct rpc_cred *nfs_file_cred(struct file *file)
nfs_file_cred(struct file *file)
{ {
struct rpc_cred *cred = NULL; if (file != NULL) {
if (file) struct nfs_open_context *ctx;
cred = (struct rpc_cred *)file->private_data;
#ifdef RPC_DEBUG ctx = (struct nfs_open_context*)file->private_data;
BUG_ON(cred && cred->cr_magic != RPCAUTH_CRED_MAGIC); return ctx->cred;
#endif }
return cred; return NULL;
} }
/* /*
...@@ -507,8 +525,6 @@ struct idmap; ...@@ -507,8 +525,6 @@ struct idmap;
enum nfs4_client_state { enum nfs4_client_state {
NFS4CLNT_OK = 0, NFS4CLNT_OK = 0,
NFS4CLNT_NEW,
NFS4CLNT_SETUP_STATE,
}; };
/* /*
...@@ -520,7 +536,6 @@ struct nfs4_client { ...@@ -520,7 +536,6 @@ struct nfs4_client {
u64 cl_clientid; /* constant */ u64 cl_clientid; /* constant */
nfs4_verifier cl_confirm; nfs4_verifier cl_confirm;
unsigned long cl_state; unsigned long cl_state;
long cl_generation;
u32 cl_lockowner_id; u32 cl_lockowner_id;
...@@ -573,9 +588,7 @@ struct nfs4_state_owner { ...@@ -573,9 +588,7 @@ struct nfs4_state_owner {
u32 so_id; /* 32-bit identifier, unique */ u32 so_id; /* 32-bit identifier, unique */
struct semaphore so_sema; struct semaphore so_sema;
u32 so_seqid; /* protected by so_sema */ u32 so_seqid; /* protected by so_sema */
unsigned int so_flags; /* protected by so_sema */
atomic_t so_count; atomic_t so_count;
long so_generation;
struct rpc_cred *so_cred; /* Associated cred */ struct rpc_cred *so_cred; /* Associated cred */
struct list_head so_states; struct list_head so_states;
...@@ -596,7 +609,8 @@ struct nfs4_state_owner { ...@@ -596,7 +609,8 @@ struct nfs4_state_owner {
struct nfs4_lock_state { struct nfs4_lock_state {
struct list_head ls_locks; /* Other lock stateids */ struct list_head ls_locks; /* Other lock stateids */
fl_owner_t ls_owner; /* POSIX lock owner */ fl_owner_t ls_owner; /* POSIX lock owner */
struct nfs4_state * ls_parent; /* Parent nfs4_state */ #define NFS_LOCK_INITIALIZED 1
int ls_flags;
u32 ls_seqid; u32 ls_seqid;
u32 ls_id; u32 ls_id;
nfs4_stateid ls_stateid; nfs4_stateid ls_stateid;
...@@ -629,6 +643,11 @@ struct nfs4_state { ...@@ -629,6 +643,11 @@ struct nfs4_state {
}; };
struct nfs4_exception {
long timeout;
int retry;
};
extern struct dentry_operations nfs4_dentry_operations; extern struct dentry_operations nfs4_dentry_operations;
extern struct inode_operations nfs4_dir_inode_operations; extern struct inode_operations nfs4_dir_inode_operations;
...@@ -639,10 +658,12 @@ extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *); ...@@ -639,10 +658,12 @@ extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
extern int nfs4_proc_async_renew(struct nfs4_client *); extern int nfs4_proc_async_renew(struct nfs4_client *);
extern int nfs4_proc_renew(struct nfs4_client *); extern int nfs4_proc_renew(struct nfs4_client *);
extern int nfs4_do_close(struct inode *, struct nfs4_state *); extern int nfs4_do_close(struct inode *, struct nfs4_state *);
int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode); extern int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode);
extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *); extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *);
extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);
extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request);
/* nfs4renewd.c */ /* nfs4renewd.c */
extern void nfs4_schedule_state_renewal(struct nfs4_client *); extern void nfs4_schedule_state_renewal(struct nfs4_client *);
...@@ -654,6 +675,7 @@ extern void init_nfsv4_state(struct nfs_server *); ...@@ -654,6 +675,7 @@ extern void init_nfsv4_state(struct nfs_server *);
extern void destroy_nfsv4_state(struct nfs_server *); extern void destroy_nfsv4_state(struct nfs_server *);
extern struct nfs4_client *nfs4_get_client(struct in_addr *); extern struct nfs4_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs4_client *clp); extern void nfs4_put_client(struct nfs4_client *clp);
extern int nfs4_init_client(struct nfs4_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
...@@ -663,14 +685,13 @@ extern void nfs4_put_open_state(struct nfs4_state *); ...@@ -663,14 +685,13 @@ extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct nfs4_state *, mode_t); extern void nfs4_close_state(struct nfs4_state *, mode_t);
extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);
extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
extern int nfs4_handle_error(struct nfs_server *, int);
extern void nfs4_schedule_state_recovery(struct nfs4_client *); extern void nfs4_schedule_state_recovery(struct nfs4_client *);
extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t); extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t);
extern struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t); extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t);
extern void nfs4_put_lock_state(struct nfs4_lock_state *state); extern void nfs4_put_lock_state(struct nfs4_lock_state *state);
extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);
extern void nfs4_notify_setlk(struct inode *, struct file_lock *, struct nfs4_lock_state *); extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_notify_unlck(struct inode *, struct file_lock *, struct nfs4_lock_state *); extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
...@@ -681,6 +702,7 @@ struct nfs4_mount_data; ...@@ -681,6 +702,7 @@ struct nfs4_mount_data;
#define destroy_nfsv4_state(server) do { } while (0) #define destroy_nfsv4_state(server) do { } while (0)
#define nfs4_put_state_owner(inode, owner) do { } while (0) #define nfs4_put_state_owner(inode, owner) do { } while (0)
#define nfs4_put_open_state(state) 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) #define nfs4_renewd_prepare_shutdown(server) do { } while (0)
#endif #endif
......
...@@ -29,14 +29,9 @@ ...@@ -29,14 +29,9 @@
struct nfs_page { struct nfs_page {
struct list_head wb_list, /* Defines state of page: */ struct list_head wb_list, /* Defines state of page: */
*wb_list_head; /* read/write/commit */ *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 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 */ 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 long wb_index; /* Offset >> PAGE_CACHE_SHIFT */
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
wb_pgbase, /* Start of page data */ wb_pgbase, /* Start of page data */
...@@ -50,9 +45,11 @@ struct nfs_page { ...@@ -50,9 +45,11 @@ struct nfs_page {
#define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags)) #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)) #define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
extern struct nfs_page *nfs_create_request(struct file *, struct inode *, extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
struct page *, struct inode *inode,
unsigned int, unsigned int); struct page *page,
unsigned int offset,
unsigned int count);
extern void nfs_clear_request(struct nfs_page *req); extern void nfs_clear_request(struct nfs_page *req);
extern void nfs_release_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *req);
...@@ -64,6 +61,7 @@ extern int nfs_scan_list(struct list_head *, struct list_head *, ...@@ -64,6 +61,7 @@ extern int nfs_scan_list(struct list_head *, struct list_head *,
extern int nfs_coalesce_requests(struct list_head *, struct list_head *, extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
unsigned int); unsigned int);
extern int nfs_wait_on_request(struct nfs_page *); 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 * Lock the page of an asynchronous request without incrementing the wb_count
...@@ -88,19 +86,6 @@ nfs_lock_request(struct nfs_page *req) ...@@ -88,19 +86,6 @@ nfs_lock_request(struct nfs_page *req)
return 1; 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 * nfs_list_remove_request - Remove a request from its wb_list
......
...@@ -235,8 +235,7 @@ struct nfs_lockres { ...@@ -235,8 +235,7 @@ struct nfs_lockres {
struct nfs_readargs { struct nfs_readargs {
struct nfs_fh * fh; struct nfs_fh * fh;
fl_owner_t lockowner; struct nfs_open_context *context;
struct nfs4_state * state;
__u64 offset; __u64 offset;
__u32 count; __u32 count;
unsigned int pgbase; unsigned int pgbase;
...@@ -259,8 +258,7 @@ struct nfs_readres { ...@@ -259,8 +258,7 @@ struct nfs_readres {
struct nfs_writeargs { struct nfs_writeargs {
struct nfs_fh * fh; struct nfs_fh * fh;
fl_owner_t lockowner; struct nfs_open_context *context;
struct nfs4_state * state;
__u64 offset; __u64 offset;
__u32 count; __u32 count;
enum nfs3_stable_how stable; enum nfs3_stable_how stable;
...@@ -597,13 +595,15 @@ struct nfs4_rename_res { ...@@ -597,13 +595,15 @@ struct nfs4_rename_res {
}; };
struct nfs4_setclientid { struct nfs4_setclientid {
nfs4_verifier sc_verifier; /* request */ const nfs4_verifier * sc_verifier; /* request */
char * sc_name; /* request */ unsigned int sc_name_len;
char sc_name[32]; /* request */
u32 sc_prog; /* request */ u32 sc_prog; /* request */
unsigned int sc_netid_len;
char sc_netid[4]; /* request */ char sc_netid[4]; /* request */
unsigned int sc_uaddr_len;
char sc_uaddr[24]; /* request */ char sc_uaddr[24]; /* request */
u32 sc_cb_ident; /* request */ u32 sc_cb_ident; /* request */
struct nfs4_client * sc_state; /* response */
}; };
struct nfs4_statfs_arg { struct nfs4_statfs_arg {
...@@ -669,16 +669,17 @@ struct nfs_rpc_ops { ...@@ -669,16 +669,17 @@ struct nfs_rpc_ops {
int (*getroot) (struct nfs_server *, struct nfs_fh *, int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *); struct nfs_fsinfo *);
int (*getattr) (struct inode *, struct nfs_fattr *); int (*getattr) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *);
int (*setattr) (struct dentry *, struct nfs_fattr *, int (*setattr) (struct dentry *, struct nfs_fattr *,
struct iattr *); struct iattr *);
int (*lookup) (struct inode *, struct qstr *, int (*lookup) (struct inode *, struct qstr *,
struct nfs_fh *, struct nfs_fattr *); struct nfs_fh *, struct nfs_fattr *);
int (*access) (struct inode *, struct nfs_access_entry *); int (*access) (struct inode *, struct nfs_access_entry *);
int (*readlink)(struct inode *, struct page *); int (*readlink)(struct inode *, struct page *);
int (*read) (struct nfs_read_data *, struct file *); int (*read) (struct nfs_read_data *);
int (*write) (struct nfs_write_data *, struct file *); int (*write) (struct nfs_write_data *);
int (*commit) (struct nfs_write_data *, struct file *); int (*commit) (struct nfs_write_data *);
struct inode * (*create) (struct inode *, struct qstr *, struct inode * (*create) (struct inode *, struct qstr *,
struct iattr *, int); struct iattr *, int);
int (*remove) (struct inode *, struct qstr *); int (*remove) (struct inode *, struct qstr *);
...@@ -710,8 +711,6 @@ struct nfs_rpc_ops { ...@@ -710,8 +711,6 @@ struct nfs_rpc_ops {
void (*commit_setup) (struct nfs_write_data *, int how); void (*commit_setup) (struct nfs_write_data *, int how);
int (*file_open) (struct inode *, struct file *); int (*file_open) (struct inode *, struct file *);
int (*file_release) (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 *); int (*lock)(struct file *, int, struct file_lock *);
}; };
......
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