Merge branch 'devel' into next

Conflicts:

	fs/nfs/file.c

Fix up the conflict with Jon Corbet's bkl-removal tree
This commit is contained in:
Trond Myklebust 2008-07-15 18:34:16 -04:00
commit e89e896d31
35 changed files with 1851 additions and 1166 deletions

View file

@ -27,7 +27,7 @@
struct nfs_callback_data {
unsigned int users;
struct svc_serv *serv;
struct svc_rqst *rqst;
struct task_struct *task;
};
@ -91,21 +91,17 @@ nfs_callback_svc(void *vrqstp)
svc_process(rqstp);
}
unlock_kernel();
nfs_callback_info.task = NULL;
svc_exit_thread(rqstp);
return 0;
}
/*
* Bring up the server process if it is not already up.
* Bring up the callback thread if it is not already up.
*/
int nfs_callback_up(void)
{
struct svc_serv *serv = NULL;
struct svc_rqst *rqstp;
int ret = 0;
lock_kernel();
mutex_lock(&nfs_callback_mutex);
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
goto out;
@ -121,22 +117,23 @@ int nfs_callback_up(void)
nfs_callback_tcpport = ret;
dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
if (IS_ERR(rqstp)) {
ret = PTR_ERR(rqstp);
nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
if (IS_ERR(nfs_callback_info.rqst)) {
ret = PTR_ERR(nfs_callback_info.rqst);
nfs_callback_info.rqst = NULL;
goto out_err;
}
svc_sock_update_bufs(serv);
nfs_callback_info.serv = serv;
nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp,
nfs_callback_info.task = kthread_run(nfs_callback_svc,
nfs_callback_info.rqst,
"nfsv4-svc");
if (IS_ERR(nfs_callback_info.task)) {
ret = PTR_ERR(nfs_callback_info.task);
nfs_callback_info.serv = NULL;
svc_exit_thread(nfs_callback_info.rqst);
nfs_callback_info.rqst = NULL;
nfs_callback_info.task = NULL;
svc_exit_thread(rqstp);
goto out_err;
}
out:
@ -149,7 +146,6 @@ out:
if (serv)
svc_destroy(serv);
mutex_unlock(&nfs_callback_mutex);
unlock_kernel();
return ret;
out_err:
dprintk("Couldn't create callback socket or server thread; err = %d\n",
@ -159,17 +155,19 @@ out_err:
}
/*
* Kill the server process if it is not already down.
* Kill the callback thread if it's no longer being used.
*/
void nfs_callback_down(void)
{
lock_kernel();
mutex_lock(&nfs_callback_mutex);
nfs_callback_info.users--;
if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL)
if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
kthread_stop(nfs_callback_info.task);
svc_exit_thread(nfs_callback_info.rqst);
nfs_callback_info.rqst = NULL;
nfs_callback_info.task = NULL;
}
mutex_unlock(&nfs_callback_mutex);
unlock_kernel();
}
static int nfs_callback_authenticate(struct svc_rqst *rqstp)

View file

@ -431,14 +431,14 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
{
to->to_initval = timeo * HZ / 10;
to->to_retries = retrans;
if (!to->to_retries)
to->to_retries = 2;
switch (proto) {
case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA:
if (to->to_retries == 0)
to->to_retries = NFS_DEF_TCP_RETRANS;
if (to->to_initval == 0)
to->to_initval = 60 * HZ;
to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
to->to_initval = NFS_MAX_TCP_TIMEOUT;
to->to_increment = to->to_initval;
@ -450,14 +450,17 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_exponential = 0;
break;
case XPRT_TRANSPORT_UDP:
default:
if (to->to_retries == 0)
to->to_retries = NFS_DEF_UDP_RETRANS;
if (!to->to_initval)
to->to_initval = 11 * HZ / 10;
to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
to->to_initval = NFS_MAX_UDP_TIMEOUT;
to->to_maxval = NFS_MAX_UDP_TIMEOUT;
to->to_exponential = 1;
break;
default:
BUG();
}
}

View file

@ -133,8 +133,11 @@ nfs_opendir(struct inode *inode, struct file *filp)
{
int res;
dfprintk(VFS, "NFS: opendir(%s/%ld)\n",
inode->i_sb->s_id, inode->i_ino);
dfprintk(FILE, "NFS: open dir(%s/%s)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name);
nfs_inc_stats(inode, NFSIOS_VFSOPEN);
lock_kernel();
/* Call generic open code in order to cache credentials */
@ -528,7 +531,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct nfs_fattr fattr;
long res;
dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n",
dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long long)filp->f_pos);
nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);
@ -595,7 +598,7 @@ out:
unlock_kernel();
if (res > 0)
res = 0;
dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n",
dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
res);
return res;
@ -603,7 +606,15 @@ out:
static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
{
mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n",
dentry->d_parent->d_name.name,
dentry->d_name.name,
offset, origin);
mutex_lock(&inode->i_mutex);
switch (origin) {
case 1:
offset += filp->f_pos;
@ -619,7 +630,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
nfs_file_open_context(filp)->dir_cookie = 0;
}
out:
mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
mutex_unlock(&inode->i_mutex);
return offset;
}
@ -629,10 +640,11 @@ out:
*/
static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
{
dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n",
dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
datasync);
nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC);
return 0;
}

View file

@ -890,7 +890,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
count = iov_length(iov, nr_segs);
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
dfprintk(FILE, "NFS: direct read(%s/%s, %zd@%Ld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
count, (long long) pos);
@ -947,7 +947,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
count = iov_length(iov, nr_segs);
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
dfprintk(FILE, "NFS: direct write(%s/%s, %zd@%Ld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
count, (long long) pos);

View file

@ -50,7 +50,7 @@ static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
static int nfs_file_flush(struct file *, fl_owner_t id);
static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
@ -72,7 +72,7 @@ const struct file_operations nfs_file_operations = {
.open = nfs_file_open,
.flush = nfs_file_flush,
.release = nfs_file_release,
.fsync = nfs_fsync,
.fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
@ -119,13 +119,17 @@ nfs_file_open(struct inode *inode, struct file *filp)
{
int res;
dprintk("NFS: open file(%s/%s)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name);
res = nfs_check_flags(filp->f_flags);
if (res)
return res;
nfs_inc_stats(inode, NFSIOS_VFSOPEN);
lock_kernel();
res = NFS_PROTO(inode)->file_open(inode, filp);
res = nfs_open(inode, filp);
unlock_kernel();
return res;
}
@ -133,11 +137,17 @@ nfs_file_open(struct inode *inode, struct file *filp)
static int
nfs_file_release(struct inode *inode, struct file *filp)
{
struct dentry *dentry = filp->f_path.dentry;
dprintk("NFS: release(%s/%s)\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
/* Ensure that dirty pages are flushed out with the right creds */
if (filp->f_mode & FMODE_WRITE)
nfs_wb_all(filp->f_path.dentry->d_inode);
nfs_wb_all(dentry->d_inode);
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
return NFS_PROTO(inode)->file_release(inode, filp);
return nfs_release(inode, filp);
}
/**
@ -171,6 +181,12 @@ force_reval:
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
{
loff_t loff;
dprintk("NFS: llseek file(%s/%s, %lld, %d)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name,
offset, origin);
/* origin == SEEK_END => we must revalidate the cached file length */
if (origin == SEEK_END) {
struct inode *inode = filp->f_mapping->host;
@ -185,7 +201,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
}
/*
* Helper for nfs_file_flush() and nfs_fsync()
* Helper for nfs_file_flush() and nfs_file_fsync()
*
* Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
* disk, but it retrieves and clears ctx->error after synching, despite
@ -211,16 +227,18 @@ static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
/*
* Flush all dirty pages, and check for write errors.
*
*/
static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = file->f_path.dentry->d_inode;
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
int status;
dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
dprintk("NFS: flush(%s/%s)\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
if ((file->f_mode & FMODE_WRITE) == 0)
return 0;
@ -245,7 +263,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_read(iocb, iov, nr_segs, pos);
dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
dprintk("NFS: read(%s/%s, %lu@%lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long) pos);
@ -265,7 +283,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
struct inode *inode = dentry->d_inode;
ssize_t res;
dfprintk(VFS, "nfs: splice_read(%s/%s, %lu@%Lu)\n",
dprintk("NFS: splice_read(%s/%s, %lu@%Lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long long) *ppos);
@ -282,7 +300,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
struct inode *inode = dentry->d_inode;
int status;
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
dprintk("NFS: mmap(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
status = nfs_revalidate_mapping(inode, file->f_mapping);
@ -300,12 +318,14 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
* whether any write errors occurred for this process.
*/
static int
nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode;
dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
dprintk("NFS: fsync file(%s/%s) datasync %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
datasync);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
return nfs_do_fsync(ctx, inode);
@ -328,6 +348,11 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
struct page *page;
index = pos >> PAGE_CACHE_SHIFT;
dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
mapping->host->i_ino, len, (long long) pos);
page = __grab_cache_page(mapping, index);
if (!page)
return -ENOMEM;
@ -348,6 +373,31 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
int status;
dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
mapping->host->i_ino, len, (long long) pos);
/*
* Zero any uninitialised parts of the page, and then mark the page
* as up to date if it turns out that we're extending the file.
*/
if (!PageUptodate(page)) {
unsigned pglen = nfs_page_length(page);
unsigned end = offset + len;
if (pglen == 0) {
zero_user_segments(page, 0, offset,
end, PAGE_CACHE_SIZE);
SetPageUptodate(page);
} else if (end >= pglen) {
zero_user_segment(page, end, PAGE_CACHE_SIZE);
if (offset == 0)
SetPageUptodate(page);
} else
zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
}
lock_kernel();
status = nfs_updatepage(file, page, offset, copied);
unlock_kernel();
@ -362,6 +412,8 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
static void nfs_invalidate_page(struct page *page, unsigned long offset)
{
dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset);
if (offset != 0)
return;
/* Cancel any unstarted writes on this page */
@ -370,13 +422,20 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
static int nfs_release_page(struct page *page, gfp_t gfp)
{
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
/* If PagePrivate() is set, then the page is not freeable */
return 0;
}
static int nfs_launder_page(struct page *page)
{
return nfs_wb_page(page->mapping->host, page);
struct inode *inode = page->mapping->host;
dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
inode->i_ino, (long long)page_offset(page));
return nfs_wb_page(inode, page);
}
const struct address_space_operations nfs_file_aops = {
@ -396,13 +455,19 @@ const struct address_space_operations nfs_file_aops = {
static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
{
struct file *filp = vma->vm_file;
struct dentry *dentry = filp->f_path.dentry;
unsigned pagelen;
int ret = -EINVAL;
struct address_space *mapping;
dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
filp->f_mapping->host->i_ino,
(long long)page_offset(page));
lock_page(page);
mapping = page->mapping;
if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping)
if (mapping != dentry->d_inode->i_mapping)
goto out_unlock;
ret = 0;
@ -450,9 +515,9 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_write(iocb, iov, nr_segs, pos);
dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
dprintk("NFS: write(%s/%s, %lu@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino, (unsigned long) count, (long long) pos);
(unsigned long) count, (long long) pos);
result = -EBUSY;
if (IS_SWAPFILE(inode))
@ -586,7 +651,8 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
* This makes locking act as a cache coherency point.
*/
nfs_sync_mapping(filp->f_mapping);
nfs_zap_caches(inode);
if (!nfs_have_delegation(inode, FMODE_READ))
nfs_zap_caches(inode);
out:
return status;
}
@ -596,23 +662,35 @@ out:
*/
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{
struct inode * inode = filp->f_mapping->host;
struct inode *inode = filp->f_mapping->host;
int ret = -ENOLCK;
dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
inode->i_sb->s_id, inode->i_ino,
dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name,
fl->fl_type, fl->fl_flags,
(long long)fl->fl_start, (long long)fl->fl_end);
nfs_inc_stats(inode, NFSIOS_VFSLOCK);
/* No mandatory locks over NFS */
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
return -ENOLCK;
goto out_err;
if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
ret = NFS_PROTO(inode)->lock_check_bounds(fl);
if (ret < 0)
goto out_err;
}
if (IS_GETLK(cmd))
return do_getlk(filp, cmd, fl);
if (fl->fl_type == F_UNLCK)
return do_unlk(filp, cmd, fl);
return do_setlk(filp, cmd, fl);
ret = do_getlk(filp, cmd, fl);
else if (fl->fl_type == F_UNLCK)
ret = do_unlk(filp, cmd, fl);
else
ret = do_setlk(filp, cmd, fl);
out_err:
return ret;
}
/*
@ -620,9 +698,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
*/
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
filp->f_path.dentry->d_inode->i_sb->s_id,
filp->f_path.dentry->d_inode->i_ino,
dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name,
fl->fl_type, fl->fl_flags);
/*
@ -645,12 +723,15 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
return do_setlk(filp, cmd, fl);
}
/*
* There is no protocol support for leases, so we have no way to implement
* them correctly in the face of opens by other clients.
*/
static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
{
/*
* There is no protocol support for leases, so we have no way
* to implement them correctly in the face of opens by other
* clients.
*/
dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name, arg);
return -EINVAL;
}

View file

@ -57,8 +57,6 @@ static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
static void nfs_invalidate_inode(struct inode *);
static int nfs_update_inode(struct inode *, struct nfs_fattr *);
static void nfs_zap_acl_cache(struct inode *);
static struct kmem_cache * nfs_inode_cachep;
static inline unsigned long
@ -167,7 +165,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
}
}
static void nfs_zap_acl_cache(struct inode *inode)
void nfs_zap_acl_cache(struct inode *inode)
{
void (*clear_acl_cache)(struct inode *);
@ -347,7 +345,7 @@ out_no_inode:
goto out;
}
#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
int
nfs_setattr(struct dentry *dentry, struct iattr *attr)
@ -369,7 +367,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
/* Optimization: if the end result is no change, don't RPC */
attr->ia_valid &= NFS_VALID_ATTRS;
if (attr->ia_valid == 0)
if ((attr->ia_valid & ~ATTR_FILE) == 0)
return 0;
lock_kernel();

View file

@ -150,6 +150,7 @@ extern void nfs_clear_inode(struct inode *);
#ifdef CONFIG_NFS_V4
extern void nfs4_clear_inode(struct inode *);
#endif
void nfs_zap_acl_cache(struct inode *inode);
/* super.c */
extern struct file_system_type nfs_xdev_fs_type;

View file

@ -5,135 +5,41 @@
*
* Copyright (C) 2005, 2006 Chuck Lever <cel@netapp.com>
*
* NFS client per-mount statistics provide information about the health of
* the NFS client and the health of each NFS mount point. Generally these
* are not for detailed problem diagnosis, but simply to indicate that there
* is a problem.
*
* These counters are not meant to be human-readable, but are meant to be
* integrated into system monitoring tools such as "sar" and "iostat". As
* such, the counters are sampled by the tools over time, and are never
* zeroed after a file system is mounted. Moving averages can be computed
* by the tools by taking the difference between two instantaneous samples
* and dividing that by the time between the samples.
*/
#ifndef _NFS_IOSTAT
#define _NFS_IOSTAT
#define NFS_IOSTAT_VERS "1.0"
/*
* NFS byte counters
*
* 1. SERVER - the number of payload bytes read from or written to the
* server by the NFS client via an NFS READ or WRITE request.
*
* 2. NORMAL - the number of bytes read or written by applications via
* the read(2) and write(2) system call interfaces.
*
* 3. DIRECT - the number of bytes read or written from files opened
* with the O_DIRECT flag.
*
* These counters give a view of the data throughput into and out of the NFS
* client. Comparing the number of bytes requested by an application with the
* number of bytes the client requests from the server can provide an
* indication of client efficiency (per-op, cache hits, etc).
*
* These counters can also help characterize which access methods are in
* use. DIRECT by itself shows whether there is any O_DIRECT traffic.
* NORMAL + DIRECT shows how much data is going through the system call
* interface. A large amount of SERVER traffic without much NORMAL or
* DIRECT traffic shows that applications are using mapped files.
*
* NFS page counters
*
* These count the number of pages read or written via nfs_readpage(),
* nfs_readpages(), or their write equivalents.
*/
enum nfs_stat_bytecounters {
NFSIOS_NORMALREADBYTES = 0,
NFSIOS_NORMALWRITTENBYTES,
NFSIOS_DIRECTREADBYTES,
NFSIOS_DIRECTWRITTENBYTES,
NFSIOS_SERVERREADBYTES,
NFSIOS_SERVERWRITTENBYTES,
NFSIOS_READPAGES,
NFSIOS_WRITEPAGES,
__NFSIOS_BYTESMAX,
};
/*
* NFS event counters
*
* These counters provide a low-overhead way of monitoring client activity
* without enabling NFS trace debugging. The counters show the rate at
* which VFS requests are made, and how often the client invalidates its
* data and attribute caches. This allows system administrators to monitor
* such things as how close-to-open is working, and answer questions such
* as "why are there so many GETATTR requests on the wire?"
*
* They also count anamolous events such as short reads and writes, silly
* renames due to close-after-delete, and operations that change the size
* of a file (such operations can often be the source of data corruption
* if applications aren't using file locking properly).
*/
enum nfs_stat_eventcounters {
NFSIOS_INODEREVALIDATE = 0,
NFSIOS_DENTRYREVALIDATE,
NFSIOS_DATAINVALIDATE,
NFSIOS_ATTRINVALIDATE,
NFSIOS_VFSOPEN,
NFSIOS_VFSLOOKUP,
NFSIOS_VFSACCESS,
NFSIOS_VFSUPDATEPAGE,
NFSIOS_VFSREADPAGE,
NFSIOS_VFSREADPAGES,
NFSIOS_VFSWRITEPAGE,
NFSIOS_VFSWRITEPAGES,
NFSIOS_VFSGETDENTS,
NFSIOS_VFSSETATTR,
NFSIOS_VFSFLUSH,
NFSIOS_VFSFSYNC,
NFSIOS_VFSLOCK,
NFSIOS_VFSRELEASE,
NFSIOS_CONGESTIONWAIT,
NFSIOS_SETATTRTRUNC,
NFSIOS_EXTENDWRITE,
NFSIOS_SILLYRENAME,
NFSIOS_SHORTREAD,
NFSIOS_SHORTWRITE,
NFSIOS_DELAY,
__NFSIOS_COUNTSMAX,
};
#ifdef __KERNEL__
#include <linux/percpu.h>
#include <linux/cache.h>
#include <linux/nfs_iostat.h>
struct nfs_iostats {
unsigned long long bytes[__NFSIOS_BYTESMAX];
unsigned long events[__NFSIOS_COUNTSMAX];
} ____cacheline_aligned;
static inline void nfs_inc_server_stats(struct nfs_server *server, enum nfs_stat_eventcounters stat)
static inline void nfs_inc_server_stats(const struct nfs_server *server,
enum nfs_stat_eventcounters stat)
{
struct nfs_iostats *iostats;
int cpu;
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
iostats->events[stat] ++;
iostats->events[stat]++;
put_cpu_no_resched();
}
static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat)
static inline void nfs_inc_stats(const struct inode *inode,
enum nfs_stat_eventcounters stat)
{
nfs_inc_server_stats(NFS_SERVER(inode), stat);
}
static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat_bytecounters stat, unsigned long addend)
static inline void nfs_add_server_stats(const struct nfs_server *server,
enum nfs_stat_bytecounters stat,
unsigned long addend)
{
struct nfs_iostats *iostats;
int cpu;
@ -144,7 +50,9 @@ static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat
put_cpu_no_resched();
}
static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend)
static inline void nfs_add_stats(const struct inode *inode,
enum nfs_stat_bytecounters stat,
unsigned long addend)
{
nfs_add_server_stats(NFS_SERVER(inode), stat, addend);
}
@ -160,5 +68,4 @@ static inline void nfs_free_iostats(struct nfs_iostats *stats)
free_percpu(stats);
}
#endif
#endif
#endif /* _NFS_IOSTAT */

View file

@ -5,6 +5,8 @@
#include <linux/posix_acl_xattr.h>
#include <linux/nfsacl.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
@ -205,6 +207,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
status = nfs_revalidate_inode(server, inode);
if (status < 0)
return ERR_PTR(status);
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
acl = nfs3_get_cached_acl(inode, type);
if (acl != ERR_PTR(-EAGAIN))
return acl;
@ -319,9 +323,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
dprintk("NFS call setacl\n");
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
status = rpc_call_sync(server->client_acl, &msg, 0);
spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
spin_unlock(&inode->i_lock);
nfs_access_zap_cache(inode);
nfs_zap_acl_cache(inode);
dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */

View file

@ -129,6 +129,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
int status;
dprintk("NFS call setattr\n");
if (sattr->ia_valid & ATTR_FILE)
msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0)
@ -248,6 +250,53 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page,
return status;
}
struct nfs3_createdata {
struct rpc_message msg;
union {
struct nfs3_createargs create;
struct nfs3_mkdirargs mkdir;
struct nfs3_symlinkargs symlink;
struct nfs3_mknodargs mknod;
} arg;
struct nfs3_diropres res;
struct nfs_fh fh;
struct nfs_fattr fattr;
struct nfs_fattr dir_attr;
};
static struct nfs3_createdata *nfs3_alloc_createdata(void)
{
struct nfs3_createdata *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data != NULL) {
data->msg.rpc_argp = &data->arg;
data->msg.rpc_resp = &data->res;
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
data->res.dir_attr = &data->dir_attr;
nfs_fattr_init(data->res.fattr);
nfs_fattr_init(data->res.dir_attr);
}
return data;
}
static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data)
{
int status;
status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
nfs_post_op_update_inode(dir, data->res.dir_attr);
if (status == 0)
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
return status;
}
static void nfs3_free_createdata(struct nfs3_createdata *data)
{
kfree(data);
}
/*
* Create a regular file.
* For now, we don't implement O_EXCL.
@ -256,70 +305,60 @@ static int
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags, struct nameidata *nd)
{
struct nfs_fh fhandle;
struct nfs_fattr fattr;
struct nfs_fattr dir_attr;
struct nfs3_createargs arg = {
.fh = NFS_FH(dir),
.name = dentry->d_name.name,
.len = dentry->d_name.len,
.sattr = sattr,
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
.fh = &fhandle,
.fattr = &fattr
};
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
struct nfs3_createdata *data;
mode_t mode = sattr->ia_mode;
int status;
int status = -ENOMEM;
dprintk("NFS call create %s\n", dentry->d_name.name);
arg.createmode = NFS3_CREATE_UNCHECKED;
data = nfs3_alloc_createdata();
if (data == NULL)
goto out;
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE];
data->arg.create.fh = NFS_FH(dir);
data->arg.create.name = dentry->d_name.name;
data->arg.create.len = dentry->d_name.len;
data->arg.create.sattr = sattr;
data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
if (flags & O_EXCL) {
arg.createmode = NFS3_CREATE_EXCLUSIVE;
arg.verifier[0] = jiffies;
arg.verifier[1] = current->pid;
data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE;
data->arg.create.verifier[0] = jiffies;
data->arg.create.verifier[1] = current->pid;
}
sattr->ia_mode &= ~current->fs->umask;
again:
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_refresh_inode(dir, &dir_attr);
for (;;) {
status = nfs3_do_create(dir, dentry, data);
/* If the server doesn't support the exclusive creation semantics,
* try again with simple 'guarded' mode. */
if (status == -ENOTSUPP) {
switch (arg.createmode) {
if (status != -ENOTSUPP)
break;
/* If the server doesn't support the exclusive creation
* semantics, try again with simple 'guarded' mode. */
switch (data->arg.create.createmode) {
case NFS3_CREATE_EXCLUSIVE:
arg.createmode = NFS3_CREATE_GUARDED;
data->arg.create.createmode = NFS3_CREATE_GUARDED;
break;
case NFS3_CREATE_GUARDED:
arg.createmode = NFS3_CREATE_UNCHECKED;
data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
break;
case NFS3_CREATE_UNCHECKED:
goto out;
}
goto again;
nfs_fattr_init(data->res.dir_attr);
nfs_fattr_init(data->res.fattr);
}
if (status == 0)
status = nfs_instantiate(dentry, &fhandle, &fattr);
if (status != 0)
goto out;
/* When we created the file with exclusive semantics, make
* sure we set the attributes afterwards. */
if (arg.createmode == NFS3_CREATE_EXCLUSIVE) {
if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) {
dprintk("NFS call setattr (post-create)\n");
if (!(sattr->ia_valid & ATTR_ATIME_SET))
@ -330,14 +369,15 @@ again:
/* Note: we could use a guarded setattr here, but I'm
* not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */
status = nfs3_proc_setattr(dentry, &fattr, sattr);
nfs_post_op_update_inode(dentry->d_inode, &fattr);
status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
dprintk("NFS reply setattr (post-create): %d\n", status);
if (status != 0)
goto out;
}
if (status != 0)
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
nfs3_free_createdata(data);
dprintk("NFS reply create: %d\n", status);
return status;
}
@ -452,40 +492,28 @@ static int
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
unsigned int len, struct iattr *sattr)
{
struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_attr;
struct nfs3_symlinkargs arg = {
.fromfh = NFS_FH(dir),
.fromname = dentry->d_name.name,
.fromlen = dentry->d_name.len,
.pages = &page,
.pathlen = len,
.sattr = sattr
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
.fh = &fhandle,
.fattr = &fattr
};
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
struct nfs3_createdata *data;
int status = -ENOMEM;
if (len > NFS3_MAXPATHLEN)
return -ENAMETOOLONG;
dprintk("NFS call symlink %s\n", dentry->d_name.name);
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_post_op_update_inode(dir, &dir_attr);
if (status != 0)
data = nfs3_alloc_createdata();
if (data == NULL)
goto out;
status = nfs_instantiate(dentry, &fhandle, &fattr);
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK];
data->arg.symlink.fromfh = NFS_FH(dir);
data->arg.symlink.fromname = dentry->d_name.name;
data->arg.symlink.fromlen = dentry->d_name.len;
data->arg.symlink.pages = &page;
data->arg.symlink.pathlen = len;
data->arg.symlink.sattr = sattr;
status = nfs3_do_create(dir, dentry, data);
nfs3_free_createdata(data);
out:
dprintk("NFS reply symlink: %d\n", status);
return status;
@ -494,42 +522,31 @@ out:
static int
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_attr;
struct nfs3_mkdirargs arg = {
.fh = NFS_FH(dir),
.name = dentry->d_name.name,
.len = dentry->d_name.len,
.sattr = sattr
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
.fh = &fhandle,
.fattr = &fattr
};
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR],
.rpc_argp = &arg,
.rpc_resp = &res,
};
struct nfs3_createdata *data;
int mode = sattr->ia_mode;
int status;
int status = -ENOMEM;
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
sattr->ia_mode &= ~current->fs->umask;
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_post_op_update_inode(dir, &dir_attr);
if (status != 0)
goto out;
status = nfs_instantiate(dentry, &fhandle, &fattr);
data = nfs3_alloc_createdata();
if (data == NULL)
goto out;
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
data->arg.mkdir.fh = NFS_FH(dir);
data->arg.mkdir.name = dentry->d_name.name;
data->arg.mkdir.len = dentry->d_name.len;
data->arg.mkdir.sattr = sattr;
status = nfs3_do_create(dir, dentry, data);
if (status != 0)
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
nfs3_free_createdata(data);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
@ -615,52 +632,50 @@ static int
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
dev_t rdev)
{
struct nfs_fh fh;
struct nfs_fattr fattr, dir_attr;
struct nfs3_mknodargs arg = {
.fh = NFS_FH(dir),
.name = dentry->d_name.name,
.len = dentry->d_name.len,
.sattr = sattr,
.rdev = rdev
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
.fh = &fh,
.fattr = &fattr
};
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD],
.rpc_argp = &arg,
.rpc_resp = &res,
};
struct nfs3_createdata *data;
mode_t mode = sattr->ia_mode;
int status;
switch (sattr->ia_mode & S_IFMT) {
case S_IFBLK: arg.type = NF3BLK; break;
case S_IFCHR: arg.type = NF3CHR; break;
case S_IFIFO: arg.type = NF3FIFO; break;
case S_IFSOCK: arg.type = NF3SOCK; break;
default: return -EINVAL;
}
int status = -ENOMEM;
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
MAJOR(rdev), MINOR(rdev));
sattr->ia_mode &= ~current->fs->umask;
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_post_op_update_inode(dir, &dir_attr);
if (status != 0)
data = nfs3_alloc_createdata();
if (data == NULL)
goto out;
status = nfs_instantiate(dentry, &fh, &fattr);
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
data->arg.mknod.fh = NFS_FH(dir);
data->arg.mknod.name = dentry->d_name.name;
data->arg.mknod.len = dentry->d_name.len;
data->arg.mknod.sattr = sattr;
data->arg.mknod.rdev = rdev;
switch (sattr->ia_mode & S_IFMT) {
case S_IFBLK:
data->arg.mknod.type = NF3BLK;
break;
case S_IFCHR:
data->arg.mknod.type = NF3CHR;
break;
case S_IFIFO:
data->arg.mknod.type = NF3FIFO;
break;
case S_IFSOCK:
data->arg.mknod.type = NF3SOCK;
break;
default:
status = -EINVAL;
goto out;
}
status = nfs3_do_create(dir, dentry, data);
if (status != 0)
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
nfs3_free_createdata(data);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
@ -801,8 +816,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.write_done = nfs3_write_done,
.commit_setup = nfs3_proc_commit_setup,
.commit_done = nfs3_commit_done,
.file_open = nfs_open,
.file_release = nfs_release,
.lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls,
};

View file

@ -1139,8 +1139,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
return res;
}
static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
struct iattr *sattr, struct nfs4_state *state)
static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = {
@ -1154,9 +1155,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
.server = server,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
.rpc_argp = &arg,
.rpc_resp = &res,
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
.rpc_argp = &arg,
.rpc_resp = &res,
.rpc_cred = cred,
};
unsigned long timestamp = jiffies;
int status;
@ -1166,7 +1168,6 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
/* Use that stateid */
} else if (state != NULL) {
msg.rpc_cred = state->owner->so_cred;
nfs4_copy_stateid(&arg.stateid, state, current->files);
} else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
@ -1177,15 +1178,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
return status;
}
static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
struct iattr *sattr, struct nfs4_state *state)
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_do_setattr(inode, fattr, sattr, state),
_nfs4_do_setattr(inode, cred, fattr, sattr, state),
&exception);
} while (exception.retry);
return err;
@ -1647,29 +1649,25 @@ static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr)
{
struct rpc_cred *cred;
struct inode *inode = dentry->d_inode;
struct nfs_open_context *ctx;
struct rpc_cred *cred = NULL;
struct nfs4_state *state = NULL;
int status;
nfs_fattr_init(fattr);
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
/* Search for an existing open(O_WRITE) file */
ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
if (ctx != NULL)
state = ctx->state;
if (sattr->ia_valid & ATTR_FILE) {
struct nfs_open_context *ctx;
status = nfs4_do_setattr(inode, fattr, sattr, state);
ctx = nfs_file_open_context(sattr->ia_file);
cred = ctx->cred;
state = ctx->state;
}
status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(inode, sattr);
if (ctx != NULL)
put_nfs_open_context(ctx);
put_rpccred(cred);
return status;
}
@ -1897,17 +1895,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
goto out;
}
state = nfs4_do_open(dir, &path, flags, sattr, cred);
put_rpccred(cred);
d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
goto out;
goto out_putcred;
}
d_add(dentry, igrab(state->inode));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) {
struct nfs_fattr fattr;
status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, &fattr);
@ -1916,6 +1913,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = nfs4_intent_set_file(nd, &path, state);
else
nfs4_close_sync(&path, state, flags);
out_putcred:
put_rpccred(cred);
out:
return status;
}
@ -2079,47 +2078,81 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
return err;
}
struct nfs4_createdata {
struct rpc_message msg;
struct nfs4_create_arg arg;
struct nfs4_create_res res;
struct nfs_fh fh;
struct nfs_fattr fattr;
struct nfs_fattr dir_fattr;
};
static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
struct qstr *name, struct iattr *sattr, u32 ftype)
{
struct nfs4_createdata *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data != NULL) {
struct nfs_server *server = NFS_SERVER(dir);
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
data->msg.rpc_argp = &data->arg;
data->msg.rpc_resp = &data->res;
data->arg.dir_fh = NFS_FH(dir);
data->arg.server = server;
data->arg.name = name;
data->arg.attrs = sattr;
data->arg.ftype = ftype;
data->arg.bitmask = server->attr_bitmask;
data->res.server = server;
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
data->res.dir_fattr = &data->dir_fattr;
nfs_fattr_init(data->res.fattr);
nfs_fattr_init(data->res.dir_fattr);
}
return data;
}
static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
{
int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
if (status == 0) {
update_changeattr(dir, &data->res.dir_cinfo);
nfs_post_op_update_inode(dir, data->res.dir_fattr);
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
}
return status;
}
static void nfs4_free_createdata(struct nfs4_createdata *data)
{
kfree(data);
}
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr)
{
struct nfs_server *server = NFS_SERVER(dir);
struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.ftype = NF4LNK,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fhandle,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
struct nfs4_createdata *data;
int status = -ENAMETOOLONG;
if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
goto out;
arg.u.symlink.pages = &page;
arg.u.symlink.len = len;
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
status = -ENOMEM;
data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
if (data == NULL)
goto out;
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
data->arg.u.symlink.pages = &page;
data->arg.u.symlink.len = len;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) {
update_changeattr(dir, &res.dir_cinfo);
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
status = nfs4_do_create(dir, dentry, data);
nfs4_free_createdata(data);
out:
return status;
}
@ -2140,39 +2173,17 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr)
{
struct nfs_server *server = NFS_SERVER(dir);
struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.ftype = NF4DIR,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fhandle,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
struct nfs4_createdata *data;
int status = -ENOMEM;
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) {
update_changeattr(dir, &res.dir_cinfo);
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
if (data == NULL)
goto out;
status = nfs4_do_create(dir, dentry, data);
nfs4_free_createdata(data);
out:
return status;
}
@ -2242,56 +2253,34 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev)
{
struct nfs_server *server = NFS_SERVER(dir);
struct nfs_fh fh;
struct nfs_fattr fattr, dir_fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fh,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
int mode = sattr->ia_mode;
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
struct nfs4_createdata *data;
int mode = sattr->ia_mode;
int status = -ENOMEM;
BUG_ON(!(sattr->ia_valid & ATTR_MODE));
BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
if (data == NULL)
goto out;
if (S_ISFIFO(mode))
arg.ftype = NF4FIFO;
data->arg.ftype = NF4FIFO;
else if (S_ISBLK(mode)) {
arg.ftype = NF4BLK;
arg.u.device.specdata1 = MAJOR(rdev);
arg.u.device.specdata2 = MINOR(rdev);
data->arg.ftype = NF4BLK;
data->arg.u.device.specdata1 = MAJOR(rdev);
data->arg.u.device.specdata2 = MINOR(rdev);
}
else if (S_ISCHR(mode)) {
arg.ftype = NF4CHR;
arg.u.device.specdata1 = MAJOR(rdev);
arg.u.device.specdata2 = MINOR(rdev);
data->arg.ftype = NF4CHR;
data->arg.u.device.specdata1 = MAJOR(rdev);
data->arg.u.device.specdata2 = MINOR(rdev);
}
else
arg.ftype = NF4SOCK;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (status == 0) {
update_changeattr(dir, &res.dir_cinfo);
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fh, &fattr);
}
status = nfs4_do_create(dir, dentry, data);
nfs4_free_createdata(data);
out:
return status;
}
@ -2706,6 +2695,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
ret = nfs_revalidate_inode(server, inode);
if (ret < 0)
return ret;
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen);
if (ret != -ENOENT)
return ret;
@ -2733,7 +2724,8 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
nfs_inode_return_delegation(inode);
buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
nfs_zap_caches(inode);
nfs_access_zap_cache(inode);
nfs_zap_acl_cache(inode);
return ret;
}
@ -2767,8 +2759,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
task->tk_status = 0;
return -EAGAIN;
case -NFS4ERR_DELAY:
nfs_inc_server_stats((struct nfs_server *) server,
NFSIOS_DELAY);
nfs_inc_server_stats(server, NFSIOS_DELAY);
case -NFS4ERR_GRACE:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
task->tk_status = 0;
@ -2933,7 +2924,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
{
long timeout;
long timeout = 0;
int err;
do {
err = _nfs4_proc_setclientid_confirm(clp, cred);
@ -3725,8 +3716,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.write_done = nfs4_write_done,
.commit_setup = nfs4_proc_commit_setup,
.commit_done = nfs4_commit_done,
.file_open = nfs_open,
.file_release = nfs_release,
.lock = nfs4_proc_lock,
.clear_acl_cache = nfs4_zap_acl_attr,
};

View file

@ -1,6 +1,4 @@
/*
* $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
* Allow an NFS filesystem to be mounted as root. The way this works is:
@ -297,10 +295,10 @@ static int __init root_nfs_name(char *name)
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
nfs_data.rsize = NFS_DEF_FILE_IO_SIZE;
nfs_data.wsize = NFS_DEF_FILE_IO_SIZE;
nfs_data.acregmin = 3;
nfs_data.acregmax = 60;
nfs_data.acdirmin = 30;
nfs_data.acdirmax = 60;
nfs_data.acregmin = NFS_DEF_ACREGMIN;
nfs_data.acregmax = NFS_DEF_ACREGMAX;
nfs_data.acdirmin = NFS_DEF_ACDIRMIN;
nfs_data.acdirmax = NFS_DEF_ACDIRMAX;
strcpy(buf, NFS_ROOT);
/* Process options received from the remote server */

View file

@ -129,6 +129,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
sattr->ia_mode &= S_IALLUGO;
dprintk("NFS call setattr\n");
if (sattr->ia_valid & ATTR_FILE)
msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0)
@ -598,6 +600,29 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
}
/* Helper functions for NFS lock bounds checking */
#define NFS_LOCK32_OFFSET_MAX ((__s32)0x7fffffffUL)
static int nfs_lock_check_bounds(const struct file_lock *fl)
{
__s32 start, end;
start = (__s32)fl->fl_start;
if ((loff_t)start != fl->fl_start)
goto out_einval;
if (fl->fl_end != OFFSET_MAX) {
end = (__s32)fl->fl_end;
if ((loff_t)end != fl->fl_end)
goto out_einval;
} else
end = NFS_LOCK32_OFFSET_MAX;
if (start < 0 || start > end)
goto out_einval;
return 0;
out_einval:
return -EINVAL;
}
const struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */
@ -630,7 +655,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.write_setup = nfs_proc_write_setup,
.write_done = nfs_write_done,
.commit_setup = nfs_proc_commit_setup,
.file_open = nfs_open,
.file_release = nfs_release,
.lock = nfs_proc_lock,
.lock_check_bounds = nfs_lock_check_bounds,
};

File diff suppressed because it is too large Load diff

View file

@ -34,9 +34,6 @@
/*
* Local function declarations
*/
static struct nfs_page * nfs_update_request(struct nfs_open_context*,
struct page *,
unsigned int, unsigned int);
static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
struct inode *inode, int ioflags);
static void nfs_redirty_request(struct nfs_page *req);
@ -169,29 +166,6 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
SetPageUptodate(page);
}
static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
unsigned int offset, unsigned int count)
{
struct nfs_page *req;
int ret;
for (;;) {
req = nfs_update_request(ctx, page, offset, count);
if (!IS_ERR(req))
break;
ret = PTR_ERR(req);
if (ret != -EBUSY)
return ret;
ret = nfs_wb_page(page->mapping->host, page);
if (ret != 0)
return ret;
}
/* Update file length */
nfs_grow_file(page, offset, count);
nfs_clear_page_tag_locked(req);
return 0;
}
static int wb_priority(struct writeback_control *wbc)
{
if (wbc->for_reclaim)
@ -268,12 +242,9 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
return ret;
spin_lock(&inode->i_lock);
}
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
/* This request is marked for commit */
if (test_bit(PG_CLEAN, &req->wb_flags)) {
spin_unlock(&inode->i_lock);
nfs_clear_page_tag_locked(req);
nfs_pageio_complete(pgio);
return 0;
BUG();
}
if (nfs_set_page_writeback(page) != 0) {
spin_unlock(&inode->i_lock);
@ -355,11 +326,19 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
/*
* Insert a write request into an inode
*/
static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
{
struct nfs_inode *nfsi = NFS_I(inode);
int error;
error = radix_tree_preload(GFP_NOFS);
if (error != 0)
goto out;
/* Lock the request! */
nfs_lock_request_dontget(req);
spin_lock(&inode->i_lock);
error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
BUG_ON(error);
if (!nfsi->npages) {
@ -373,6 +352,10 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
kref_get(&req->wb_kref);
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
NFS_PAGE_TAG_LOCKED);
spin_unlock(&inode->i_lock);
radix_tree_preload_end();
out:
return error;
}
/*
@ -405,19 +388,6 @@ nfs_mark_request_dirty(struct nfs_page *req)
__set_page_dirty_nobuffers(req->wb_page);
}
/*
* Check if a request is dirty
*/
static inline int
nfs_dirty_request(struct nfs_page *req)
{
struct page *page = req->wb_page;
if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags))
return 0;
return !PageWriteback(page);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
/*
* Add a request to the inode's commit list.
@ -430,7 +400,7 @@ nfs_mark_request_commit(struct nfs_page *req)
spin_lock(&inode->i_lock);
nfsi->ncommit++;
set_bit(PG_NEED_COMMIT, &(req)->wb_flags);
set_bit(PG_CLEAN, &(req)->wb_flags);
radix_tree_tag_set(&nfsi->nfs_page_tree,
req->wb_index,
NFS_PAGE_TAG_COMMIT);
@ -440,6 +410,19 @@ nfs_mark_request_commit(struct nfs_page *req)
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
}
static int
nfs_clear_request_commit(struct nfs_page *req)
{
struct page *page = req->wb_page;
if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
dec_zone_page_state(page, NR_UNSTABLE_NFS);
dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
return 1;
}
return 0;
}
static inline
int nfs_write_need_commit(struct nfs_write_data *data)
{
@ -449,7 +432,7 @@ int nfs_write_need_commit(struct nfs_write_data *data)
static inline
int nfs_reschedule_unstable_write(struct nfs_page *req)
{
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
nfs_mark_request_commit(req);
return 1;
}
@ -465,6 +448,12 @@ nfs_mark_request_commit(struct nfs_page *req)
{
}
static inline int
nfs_clear_request_commit(struct nfs_page *req)
{
return 0;
}
static inline
int nfs_write_need_commit(struct nfs_write_data *data)
{
@ -522,11 +511,8 @@ static void nfs_cancel_commit_list(struct list_head *head)
while(!list_empty(head)) {
req = nfs_list_entry(head->next);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
BDI_RECLAIMABLE);
nfs_list_remove_request(req);
clear_bit(PG_NEED_COMMIT, &(req)->wb_flags);
nfs_clear_request_commit(req);
nfs_inode_remove_request(req);
nfs_unlock_request(req);
}
@ -564,108 +550,122 @@ static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pg
#endif
/*
* Try to update any existing write request, or create one if there is none.
* In order to match, the request's credentials must match those of
* the calling process.
* Search for an existing write request, and attempt to update
* it to reflect a new dirty region on a given page.
*
* Note: Should always be called with the Page Lock held!
* If the attempt fails, then the existing request is flushed out
* to disk.
*/
static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
struct page *page, unsigned int offset, unsigned int bytes)
static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
struct page *page,
unsigned int offset,
unsigned int bytes)
{
struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host;
struct nfs_page *req, *new = NULL;
pgoff_t rqend, end;
struct nfs_page *req;
unsigned int rqend;
unsigned int end;
int error;
if (!PagePrivate(page))
return NULL;
end = offset + bytes;
spin_lock(&inode->i_lock);
for (;;) {
/* Loop over all inode entries and see if we find
* A request for the page we wish to update
*/
if (new) {
if (radix_tree_preload(GFP_NOFS)) {
nfs_release_request(new);
return ERR_PTR(-ENOMEM);
}
}
spin_lock(&inode->i_lock);
req = nfs_page_find_request_locked(page);
if (req) {
if (!nfs_set_page_tag_locked(req)) {
int error;
if (req == NULL)
goto out_unlock;
spin_unlock(&inode->i_lock);
error = nfs_wait_on_request(req);
nfs_release_request(req);
if (error < 0) {
if (new) {
radix_tree_preload_end();
nfs_release_request(new);
}
return ERR_PTR(error);
}
continue;
}
spin_unlock(&inode->i_lock);
if (new) {
radix_tree_preload_end();
nfs_release_request(new);
}
rqend = req->wb_offset + req->wb_bytes;
/*
* Tell the caller to flush out the request if
* the offsets are non-contiguous.
* Note: nfs_flush_incompatible() will already
* have flushed out requests having wrong owners.
*/
if (offset > rqend
|| end < req->wb_offset)
goto out_flushme;
if (nfs_set_page_tag_locked(req))
break;
}
if (new) {
nfs_lock_request_dontget(new);
nfs_inode_add_request(inode, new);
spin_unlock(&inode->i_lock);
radix_tree_preload_end();
req = new;
goto zero_page;
}
/* The request is locked, so wait and then retry */
spin_unlock(&inode->i_lock);
new = nfs_create_request(ctx, inode, page, offset, bytes);
if (IS_ERR(new))
return new;
error = nfs_wait_on_request(req);
nfs_release_request(req);
if (error != 0)
goto out_err;
spin_lock(&inode->i_lock);
}
/* We have a request for our page.
* If the creds don't match, or the
* page addresses don't match,
* tell the caller to wait on the conflicting
* request.
*/
rqend = req->wb_offset + req->wb_bytes;
if (req->wb_context != ctx
|| req->wb_page != page
|| !nfs_dirty_request(req)
|| offset > rqend || end < req->wb_offset) {
nfs_clear_page_tag_locked(req);
return ERR_PTR(-EBUSY);
}
if (nfs_clear_request_commit(req))
radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
req->wb_index, NFS_PAGE_TAG_COMMIT);
/* Okay, the request matches. Update the region */
if (offset < req->wb_offset) {
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = max(end, rqend) - req->wb_offset;
goto zero_page;
}
if (end > rqend)
req->wb_bytes = end - req->wb_offset;
else
req->wb_bytes = rqend - req->wb_offset;
out_unlock:
spin_unlock(&inode->i_lock);
return req;
out_flushme:
spin_unlock(&inode->i_lock);
nfs_release_request(req);
error = nfs_wb_page(inode, page);
out_err:
return ERR_PTR(error);
}
/*
* Try to update an existing write request, or create one if there is none.
*
* Note: Should always be called with the Page Lock held to prevent races
* if we have to add a new request. Also assumes that the caller has
* already called nfs_flush_incompatible() if necessary.
*/
static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
struct page *page, unsigned int offset, unsigned int bytes)
{
struct inode *inode = page->mapping->host;
struct nfs_page *req;
int error;
req = nfs_try_to_update_request(inode, page, offset, bytes);
if (req != NULL)
goto out;
req = nfs_create_request(ctx, inode, page, offset, bytes);
if (IS_ERR(req))
goto out;
error = nfs_inode_add_request(inode, req);
if (error != 0) {
nfs_release_request(req);
req = ERR_PTR(error);
}
out:
return req;
zero_page:
/* If this page might potentially be marked as up to date,
* then we need to zero any uninitalised data. */
if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
&& !PageUptodate(req->wb_page))
zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
return req;
}
static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
unsigned int offset, unsigned int count)
{
struct nfs_page *req;
req = nfs_setup_write_request(ctx, page, offset, count);
if (IS_ERR(req))
return PTR_ERR(req);
/* Update file length */
nfs_grow_file(page, offset, count);
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
nfs_clear_page_tag_locked(req);
return 0;
}
int nfs_flush_incompatible(struct file *file, struct page *page)
@ -685,8 +685,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
return 0;
do_flush = req->wb_page != page || req->wb_context != ctx
|| !nfs_dirty_request(req);
do_flush = req->wb_page != page || req->wb_context != ctx;
nfs_release_request(req);
if (!do_flush)
return 0;
@ -721,10 +720,10 @@ int nfs_updatepage(struct file *file, struct page *page,
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
dprintk("NFS: nfs_updatepage(%s/%s %d@%lld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name, count,
(long long)(page_offset(page) +offset));
(long long)(page_offset(page) + offset));
/* If we're not using byte range locks, and we know the page
* is up to date, it may be more efficient to extend the write
@ -744,7 +743,7 @@ int nfs_updatepage(struct file *file, struct page *page,
else
__set_page_dirty_nobuffers(page);
dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n",
status, (long long)i_size_read(inode));
return status;
}
@ -752,12 +751,7 @@ int nfs_updatepage(struct file *file, struct page *page,
static void nfs_writepage_release(struct nfs_page *req)
{
if (PageError(req->wb_page)) {
nfs_end_page_writeback(req->wb_page);
nfs_inode_remove_request(req);
} else if (!nfs_reschedule_unstable_write(req)) {
/* Set the PG_uptodate flag */
nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes);
if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
nfs_end_page_writeback(req->wb_page);
nfs_inode_remove_request(req);
} else
@ -834,7 +828,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
NFS_PROTO(inode)->write_setup(data, &msg);
dprintk("NFS: %5u initiated write call "
"(req %s/%Ld, %u bytes @ offset %Lu)\n",
"(req %s/%lld, %u bytes @ offset %llu)\n",
data->task.tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
@ -978,13 +972,13 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
struct nfs_page *req = data->req;
dprintk("NFS: write (%s/%Ld %d@%Ld)",
req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
dprintk("NFS: %5u write(%s/%lld %d@%lld)",
task->tk_pid,
data->req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)
NFS_FILEID(data->req->wb_context->path.dentry->d_inode),
data->req->wb_bytes, (long long)req_offset(data->req));
nfs_writeback_done(task, data);
}
@ -1058,7 +1052,8 @@ static void nfs_writeback_release_full(void *calldata)
nfs_list_remove_request(req);
dprintk("NFS: write (%s/%Ld %d@%Ld)",
dprintk("NFS: %5u write (%s/%lld %d@%lld)",
data->task.tk_pid,
req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
@ -1078,8 +1073,6 @@ static void nfs_writeback_release_full(void *calldata)
dprintk(" marked for commit\n");
goto next;
}
/* Set the PG_uptodate flag? */
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
dprintk(" OK\n");
remove_request:
nfs_end_page_writeback(page);
@ -1133,7 +1126,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
static unsigned long complain;
if (time_before(complain, jiffies)) {
dprintk("NFS: faulty NFS server %s:"
dprintk("NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)\n",
NFS_SERVER(data->inode)->nfs_client->cl_hostname,
resp->verf->committed, argp->stable);
@ -1297,12 +1290,9 @@ static void nfs_commit_release(void *calldata)
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
clear_bit(PG_NEED_COMMIT, &(req)->wb_flags);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
BDI_RECLAIMABLE);
nfs_clear_request_commit(req);
dprintk("NFS: commit (%s/%Ld %d@%Ld)",
dprintk("NFS: commit (%s/%lld %d@%lld)",
req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
@ -1318,9 +1308,6 @@ static void nfs_commit_release(void *calldata)
* returned by the server against all stored verfs. */
if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
/* We have a match */
/* Set the PG_uptodate flag */
nfs_mark_uptodate(req->wb_page, req->wb_pgbase,
req->wb_bytes);
nfs_inode_remove_request(req);
dprintk(" OK\n");
goto next;
@ -1479,7 +1466,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
goto out;
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
if (test_bit(PG_CLEAN, &req->wb_flags)) {
nfs_release_request(req);
break;
}