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:
commit
e89e896d31
35 changed files with 1851 additions and 1166 deletions
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
fs/nfs/dir.c
26
fs/nfs/dir.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
151
fs/nfs/file.c
151
fs/nfs/file.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
119
fs/nfs/iostat.h
119
fs/nfs/iostat.h
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
884
fs/nfs/super.c
884
fs/nfs/super.c
File diff suppressed because it is too large
Load diff
307
fs/nfs/write.c
307
fs/nfs/write.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue