Commit 36274526 authored by Trond Myklebust's avatar Trond Myklebust

Merge branch 'writeback'

parents 7f94ed24 e033fb51
...@@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o ...@@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o
CFLAGS_nfstrace.o += -I$(src) CFLAGS_nfstrace.o += -I$(src)
nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
direct.o pagelist.o read.o symlink.o unlink.o \ io.o direct.o pagelist.o read.o symlink.o unlink.o \
write.o namespace.o mount_clnt.o nfstrace.o write.o namespace.o mount_clnt.o nfstrace.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_SYSCTL) += sysctl.o
......
...@@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st ...@@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
return NULL; return NULL;
} }
static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res, bool may_block)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_access_entry *cache; struct nfs_access_entry *cache;
int err = -ENOENT; bool retry = true;
int err;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) for(;;) {
goto out_zap; if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
cache = nfs_access_search_rbtree(inode, cred); goto out_zap;
if (cache == NULL) cache = nfs_access_search_rbtree(inode, cred);
goto out; err = -ENOENT;
if (!nfs_have_delegated_attributes(inode) && if (cache == NULL)
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) goto out;
goto out_stale; /* Found an entry, is our attribute cache valid? */
if (!nfs_attribute_cache_expired(inode) &&
!(nfsi->cache_validity & NFS_INO_INVALID_ATTR))
break;
err = -ECHILD;
if (!may_block)
goto out;
if (!retry)
goto out_zap;
spin_unlock(&inode->i_lock);
err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (err)
return err;
spin_lock(&inode->i_lock);
retry = false;
}
res->jiffies = cache->jiffies; res->jiffies = cache->jiffies;
res->cred = cache->cred; res->cred = cache->cred;
res->mask = cache->mask; res->mask = cache->mask;
...@@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str ...@@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
out: out:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
return err; return err;
out_stale:
rb_erase(&cache->rb_node, &nfsi->access_cache);
list_del(&cache->lru);
spin_unlock(&inode->i_lock);
nfs_access_free_entry(cache);
return -ENOENT;
out_zap: out_zap:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
nfs_access_zap_cache(inode); nfs_access_zap_cache(inode);
...@@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred, ...@@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
cache = NULL; cache = NULL;
if (cache == NULL) if (cache == NULL)
goto out; goto out;
if (!nfs_have_delegated_attributes(inode) && err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode);
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) if (err)
goto out; goto out;
res->jiffies = cache->jiffies; res->jiffies = cache->jiffies;
res->cred = cache->cred; res->cred = cache->cred;
res->mask = cache->mask; res->mask = cache->mask;
err = 0;
out: out:
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
...@@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask); ...@@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask);
static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
{ {
struct nfs_access_entry cache; struct nfs_access_entry cache;
bool may_block = (mask & MAY_NOT_BLOCK) == 0;
int status; int status;
trace_nfs_access_enter(inode); trace_nfs_access_enter(inode);
status = nfs_access_get_cached_rcu(inode, cred, &cache); status = nfs_access_get_cached_rcu(inode, cred, &cache);
if (status != 0) if (status != 0)
status = nfs_access_get_cached(inode, cred, &cache); status = nfs_access_get_cached(inode, cred, &cache, may_block);
if (status == 0) if (status == 0)
goto out_cached; goto out_cached;
status = -ECHILD; status = -ECHILD;
if (mask & MAY_NOT_BLOCK) if (!may_block)
goto out; goto out;
/* Be clever: ask server to check for all possible rights */ /* Be clever: ask server to check for all possible rights */
......
...@@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, ...@@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
WARN_ON_ONCE(verfp->committed < 0); WARN_ON_ONCE(verfp->committed < 0);
} }
static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1,
const struct nfs_writeverf *v2)
{
return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier);
}
/* /*
* nfs_direct_cmp_hdr_verf - compare verifier for pgio header * nfs_direct_cmp_hdr_verf - compare verifier for pgio header
* @dreq - direct request possibly spanning multiple servers * @dreq - direct request possibly spanning multiple servers
...@@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, ...@@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
nfs_direct_set_hdr_verf(dreq, hdr); nfs_direct_set_hdr_verf(dreq, hdr);
return 0; return 0;
} }
return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &hdr->verf);
} }
/* /*
...@@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, ...@@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
if (verfp->committed < 0) if (verfp->committed < 0)
return 1; return 1;
return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &data->verf);
} }
/** /**
...@@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) ...@@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
* the iocb is still valid here if this is a synchronous request. * the iocb is still valid here if this is a synchronous request.
*/ */
static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) static void nfs_direct_complete(struct nfs_direct_req *dreq)
{ {
struct inode *inode = dreq->inode; struct inode *inode = dreq->inode;
if (dreq->iocb && write) {
loff_t pos = dreq->iocb->ki_pos + dreq->count;
spin_lock(&inode->i_lock);
if (i_size_read(inode) < pos)
i_size_write(inode, pos);
spin_unlock(&inode->i_lock);
}
if (write)
nfs_zap_mapping(inode, inode->i_mapping);
inode_dio_end(inode); inode_dio_end(inode);
if (dreq->iocb) { if (dreq->iocb) {
...@@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) ...@@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
} }
out_put: out_put:
if (put_dreq(dreq)) if (put_dreq(dreq))
nfs_direct_complete(dreq, false); nfs_direct_complete(dreq);
hdr->release(hdr); hdr->release(hdr);
} }
...@@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
} }
if (put_dreq(dreq)) if (put_dreq(dreq))
nfs_direct_complete(dreq, false); nfs_direct_complete(dreq);
return 0; return 0;
} }
...@@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (!count) if (!count)
goto out; goto out;
inode_lock(inode);
result = nfs_sync_mapping(mapping);
if (result)
goto out_unlock;
task_io_account_read(count); task_io_account_read(count);
result = -ENOMEM; result = -ENOMEM;
dreq = nfs_direct_req_alloc(); dreq = nfs_direct_req_alloc();
if (dreq == NULL) if (dreq == NULL)
goto out_unlock; goto out;
dreq->inode = inode; dreq->inode = inode;
dreq->bytes_left = dreq->max_count = count; dreq->bytes_left = dreq->max_count = count;
...@@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
dreq->iocb = iocb; dreq->iocb = iocb;
nfs_start_io_direct(inode);
NFS_I(inode)->read_io += count; NFS_I(inode)->read_io += count;
result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
inode_unlock(inode); nfs_end_io_direct(inode);
if (!result) { if (!result) {
result = nfs_direct_wait(dreq); result = nfs_direct_wait(dreq);
...@@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
iocb->ki_pos += result; iocb->ki_pos += result;
} }
nfs_direct_req_release(dreq);
return result;
out_release: out_release:
nfs_direct_req_release(dreq); nfs_direct_req_release(dreq);
out_unlock:
inode_unlock(inode);
out: out:
return result; return result;
} }
...@@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) ...@@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
dreq->count = 0; dreq->count = 0;
dreq->verf.committed = NFS_INVALID_STABLE_HOW;
nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
for (i = 0; i < dreq->mirror_count; i++) for (i = 0; i < dreq->mirror_count; i++)
dreq->mirrors[i].count = 0; dreq->mirrors[i].count = 0;
get_dreq(dreq); get_dreq(dreq);
...@@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) ...@@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
nfs_direct_write_reschedule(dreq); nfs_direct_write_reschedule(dreq);
break; break;
default: default:
nfs_direct_complete(dreq, true); nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
nfs_direct_complete(dreq);
} }
} }
...@@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
{ {
ssize_t result = -EINVAL; ssize_t result = -EINVAL;
size_t count;
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
file, iov_iter_count(iter), (long long) iocb->ki_pos); file, iov_iter_count(iter), (long long) iocb->ki_pos);
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, result = generic_write_checks(iocb, iter);
iov_iter_count(iter)); if (result <= 0)
return result;
count = result;
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
pos = iocb->ki_pos; pos = iocb->ki_pos;
end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT; end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT;
inode_lock(inode); task_io_account_write(count);
result = nfs_sync_mapping(mapping);
if (result)
goto out_unlock;
if (mapping->nrpages) {
result = invalidate_inode_pages2_range(mapping,
pos >> PAGE_SHIFT, end);
if (result)
goto out_unlock;
}
task_io_account_write(iov_iter_count(iter));
result = -ENOMEM; result = -ENOMEM;
dreq = nfs_direct_req_alloc(); dreq = nfs_direct_req_alloc();
if (!dreq) if (!dreq)
goto out_unlock; goto out;
dreq->inode = inode; dreq->inode = inode;
dreq->bytes_left = dreq->max_count = iov_iter_count(iter); dreq->bytes_left = dreq->max_count = count;
dreq->io_start = pos; dreq->io_start = pos;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx); l_ctx = nfs_get_lock_context(dreq->ctx);
...@@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
dreq->iocb = iocb; dreq->iocb = iocb;
nfs_start_io_direct(inode);
result = nfs_direct_write_schedule_iovec(dreq, iter, pos); result = nfs_direct_write_schedule_iovec(dreq, iter, pos);
if (mapping->nrpages) { if (mapping->nrpages) {
...@@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
pos >> PAGE_SHIFT, end); pos >> PAGE_SHIFT, end);
} }
inode_unlock(inode); nfs_end_io_direct(inode);
if (!result) { if (!result) {
result = nfs_direct_wait(dreq); result = nfs_direct_wait(dreq);
if (result > 0) { if (result > 0) {
struct inode *inode = mapping->host;
iocb->ki_pos = pos + result; iocb->ki_pos = pos + result;
spin_lock(&inode->i_lock);
if (i_size_read(inode) < iocb->ki_pos)
i_size_write(inode, iocb->ki_pos);
spin_unlock(&inode->i_lock);
/* XXX: should check the generic_write_sync retval */ /* XXX: should check the generic_write_sync retval */
generic_write_sync(iocb, result); generic_write_sync(iocb, result);
} }
} }
nfs_direct_req_release(dreq);
return result;
out_release: out_release:
nfs_direct_req_release(dreq); nfs_direct_req_release(dreq);
out_unlock: out:
inode_unlock(inode);
return result; return result;
} }
......
...@@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) ...@@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
iocb->ki_filp, iocb->ki_filp,
iov_iter_count(to), (unsigned long) iocb->ki_pos); iov_iter_count(to), (unsigned long) iocb->ki_pos);
result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping); nfs_start_io_read(inode);
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
if (!result) { if (!result) {
result = generic_file_read_iter(iocb, to); result = generic_file_read_iter(iocb, to);
if (result > 0) if (result > 0)
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
} }
nfs_end_io_read(inode);
return result; return result;
} }
EXPORT_SYMBOL_GPL(nfs_file_read); EXPORT_SYMBOL_GPL(nfs_file_read);
...@@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, ...@@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
filp, (unsigned long) count, (unsigned long long) *ppos); filp, (unsigned long) count, (unsigned long long) *ppos);
res = nfs_revalidate_mapping_protected(inode, filp->f_mapping); nfs_start_io_read(inode);
res = nfs_revalidate_mapping(inode, filp->f_mapping);
if (!res) { if (!res) {
res = generic_file_splice_read(filp, ppos, pipe, count, flags); res = generic_file_splice_read(filp, ppos, pipe, count, flags);
if (res > 0) if (res > 0)
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res);
} }
nfs_end_io_read(inode);
return res; return res;
} }
EXPORT_SYMBOL_GPL(nfs_file_splice_read); EXPORT_SYMBOL_GPL(nfs_file_splice_read);
...@@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
trace_nfs_fsync_enter(inode); trace_nfs_fsync_enter(inode);
inode_dio_wait(inode);
do { do {
ret = filemap_write_and_wait_range(inode->i_mapping, start, end); ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
if (ret != 0) if (ret != 0)
break; break;
inode_lock(inode);
ret = nfs_file_fsync_commit(file, start, end, datasync); ret = nfs_file_fsync_commit(file, start, end, datasync);
if (!ret) if (!ret)
ret = pnfs_sync_inode(inode, !!datasync); ret = pnfs_sync_inode(inode, !!datasync);
inode_unlock(inode);
/* /*
* If nfs_file_fsync_commit detected a server reboot, then * If nfs_file_fsync_commit detected a server reboot, then
* resend all dirty pages that might have been covered by * resend all dirty pages that might have been covered by
...@@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, ...@@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
file, mapping->host->i_ino, len, (long long) pos); file, mapping->host->i_ino, len, (long long) pos);
start: start:
/*
* Prevent starvation issues if someone is doing a consistency
* sync-to-disk
*/
ret = wait_on_bit_action(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
nfs_wait_bit_killable, TASK_KILLABLE);
if (ret)
return ret;
/*
* Wait for O_DIRECT to complete
*/
inode_dio_wait(mapping->host);
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset, ...@@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset,
*/ */
static int nfs_release_page(struct page *page, gfp_t gfp) static int nfs_release_page(struct page *page, gfp_t gfp)
{ {
struct address_space *mapping = page->mapping;
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
/* Always try to initiate a 'commit' if relevant, but only
* wait for it if the caller allows blocking. Even then,
* only wait 1 second and only if the 'bdi' is not congested.
* Waiting indefinitely can cause deadlocks when the NFS
* server is on this machine, when a new TCP connection is
* needed and in other rare cases. There is no particular
* need to wait extensively here. A short wait has the
* benefit that someone else can worry about the freezer.
*/
if (mapping) {
struct nfs_server *nfss = NFS_SERVER(mapping->host);
nfs_commit_inode(mapping->host, 0);
if (gfpflags_allow_blocking(gfp) &&
!bdi_write_congested(&nfss->backing_dev_info)) {
wait_on_page_bit_killable_timeout(page, PG_private,
HZ);
if (PagePrivate(page))
set_bdi_congested(&nfss->backing_dev_info,
BLK_RW_ASYNC);
}
}
/* If PagePrivate() is set, then the page is not freeable */ /* If PagePrivate() is set, then the page is not freeable */
if (PagePrivate(page)) if (PagePrivate(page))
return 0; return 0;
...@@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
filp, filp->f_mapping->host->i_ino, filp, filp->f_mapping->host->i_ino,
(long long)page_offset(page)); (long long)page_offset(page));
sb_start_pagefault(inode->i_sb);
/* make sure the cache has finished storing the page */ /* make sure the cache has finished storing the page */
nfs_fscache_wait_on_page_write(NFS_I(inode), page); nfs_fscache_wait_on_page_write(NFS_I(inode), page);
...@@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
out_unlock: out_unlock:
unlock_page(page); unlock_page(page);
out: out:
sb_end_pagefault(inode->i_sb);
return ret; return ret;
} }
...@@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
unsigned long written = 0; unsigned long written = 0;
ssize_t result; ssize_t result;
size_t count = iov_iter_count(from);
result = nfs_key_timeout_notify(file, inode); result = nfs_key_timeout_notify(file, inode);
if (result) if (result)
return result; return result;
if (iocb->ki_flags & IOCB_DIRECT) { if (iocb->ki_flags & IOCB_DIRECT)
result = generic_write_checks(iocb, from);
if (result <= 0)
return result;
return nfs_file_direct_write(iocb, from); return nfs_file_direct_write(iocb, from);
}
dprintk("NFS: write(%pD2, %zu@%Ld)\n", dprintk("NFS: write(%pD2, %zu@%Ld)\n",
file, count, (long long) iocb->ki_pos); file, iov_iter_count(from), (long long) iocb->ki_pos);
result = -EBUSY;
if (IS_SWAPFILE(inode)) if (IS_SWAPFILE(inode))
goto out_swapfile; goto out_swapfile;
/* /*
...@@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
goto out; goto out;
} }
result = count; nfs_start_io_write(inode);
if (!count) result = generic_write_checks(iocb, from);
if (result > 0) {
current->backing_dev_info = inode_to_bdi(inode);
result = generic_perform_write(file, from, iocb->ki_pos);
current->backing_dev_info = NULL;
}
nfs_end_io_write(inode);
if (result <= 0)
goto out; goto out;
result = generic_file_write_iter(iocb, from); written = generic_write_sync(iocb, result);
if (result > 0) iocb->ki_pos += written;
written = result;
/* Return error values */ /* Return error values */
if (result >= 0 && nfs_need_check_write(file, inode)) { if (nfs_need_check_write(file, inode)) {
int err = vfs_fsync(file, 0); int err = vfs_fsync(file, 0);
if (err < 0) if (err < 0)
result = err; result = err;
} }
if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
out: out:
return result; return result;
out_swapfile: out_swapfile:
printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); printk(KERN_INFO "NFS: attempt to write to active swap file!\n");
goto out; return -EBUSY;
} }
EXPORT_SYMBOL_GPL(nfs_file_write); EXPORT_SYMBOL_GPL(nfs_file_write);
...@@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) ...@@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
return status; return status;
} }
static int
is_time_granular(struct timespec *ts) {
return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
}
static int static int
do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{ {
...@@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) ...@@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
* This makes locking act as a cache coherency point. * This makes locking act as a cache coherency point.
*/ */
nfs_sync_mapping(filp->f_mapping); nfs_sync_mapping(filp->f_mapping);
if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) { if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
if (is_time_granular(&NFS_SERVER(inode)->time_delta)) nfs_zap_mapping(inode, filp->f_mapping);
__nfs_revalidate_inode(NFS_SERVER(inode), inode);
else
nfs_zap_caches(inode);
}
out: out:
return status; return status;
} }
......
...@@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task, ...@@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task,
static void static void
filelayout_set_layoutcommit(struct nfs_pgio_header *hdr) filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
{ {
loff_t end_offs = 0;
if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
hdr->res.verf->committed != NFS_DATA_SYNC) hdr->res.verf->committed == NFS_FILE_SYNC)
return; return;
if (hdr->res.verf->committed == NFS_DATA_SYNC)
end_offs = hdr->mds_offset + (loff_t)hdr->res.count;
pnfs_set_layoutcommit(hdr->inode, hdr->lseg, /* Note: if the write is unstable, don't set end_offs until commit */
hdr->mds_offset + hdr->res.count); pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs);
dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
} }
...@@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task, ...@@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task,
} }
filelayout_set_layoutcommit(hdr); filelayout_set_layoutcommit(hdr);
/* zero out the fattr */
hdr->fattr.valid = 0;
if (task->tk_status >= 0)
nfs_writeback_update_inode(hdr);
return 0; return 0;
} }
...@@ -375,8 +384,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task, ...@@ -375,8 +384,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
return -EAGAIN; return -EAGAIN;
} }
if (data->verf.committed == NFS_UNSTABLE) pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
return 0; return 0;
} }
......
...@@ -1325,15 +1325,16 @@ ff_layout_need_layoutcommit(struct pnfs_layout_segment *lseg) ...@@ -1325,15 +1325,16 @@ ff_layout_need_layoutcommit(struct pnfs_layout_segment *lseg)
* we always send layoutcommit after DS writes. * we always send layoutcommit after DS writes.
*/ */
static void static void
ff_layout_set_layoutcommit(struct nfs_pgio_header *hdr) ff_layout_set_layoutcommit(struct inode *inode,
struct pnfs_layout_segment *lseg,
loff_t end_offset)
{ {
if (!ff_layout_need_layoutcommit(hdr->lseg)) if (!ff_layout_need_layoutcommit(lseg))
return; return;
pnfs_set_layoutcommit(hdr->inode, hdr->lseg, pnfs_set_layoutcommit(inode, lseg, end_offset);
hdr->mds_offset + hdr->res.count); dprintk("%s inode %lu pls_end_pos %llu\n", __func__, inode->i_ino,
dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, (unsigned long long) NFS_I(inode)->layout->plh_lwb);
(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
} }
static bool static bool
...@@ -1469,6 +1470,7 @@ static void ff_layout_read_release(void *data) ...@@ -1469,6 +1470,7 @@ static void ff_layout_read_release(void *data)
static int ff_layout_write_done_cb(struct rpc_task *task, static int ff_layout_write_done_cb(struct rpc_task *task,
struct nfs_pgio_header *hdr) struct nfs_pgio_header *hdr)
{ {
loff_t end_offs = 0;
int err; int err;
trace_nfs4_pnfs_write(hdr, task->tk_status); trace_nfs4_pnfs_write(hdr, task->tk_status);
...@@ -1494,7 +1496,10 @@ static int ff_layout_write_done_cb(struct rpc_task *task, ...@@ -1494,7 +1496,10 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
if (hdr->res.verf->committed == NFS_FILE_SYNC || if (hdr->res.verf->committed == NFS_FILE_SYNC ||
hdr->res.verf->committed == NFS_DATA_SYNC) hdr->res.verf->committed == NFS_DATA_SYNC)
ff_layout_set_layoutcommit(hdr); end_offs = hdr->mds_offset + (loff_t)hdr->res.count;
/* Note: if the write is unstable, don't set end_offs until commit */
ff_layout_set_layoutcommit(hdr->inode, hdr->lseg, end_offs);
/* zero out fattr since we don't care DS attr at all */ /* zero out fattr since we don't care DS attr at all */
hdr->fattr.valid = 0; hdr->fattr.valid = 0;
...@@ -1530,9 +1535,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task, ...@@ -1530,9 +1535,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
return -EAGAIN; return -EAGAIN;
} }
if (data->verf.committed == NFS_UNSTABLE ff_layout_set_layoutcommit(data->inode, data->lseg, data->lwb);
&& ff_layout_need_layoutcommit(data->lseg))
pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
return 0; return 0;
} }
......
...@@ -662,9 +662,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -662,9 +662,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
trace_nfs_getattr_enter(inode); trace_nfs_getattr_enter(inode);
/* Flush out writes to the server in order to update c/mtime. */ /* Flush out writes to the server in order to update c/mtime. */
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
inode_lock(inode); err = filemap_write_and_wait(inode->i_mapping);
err = nfs_sync_inode(inode);
inode_unlock(inode);
if (err) if (err)
goto out; goto out;
} }
...@@ -879,7 +877,10 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx) ...@@ -879,7 +877,10 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
list_add(&ctx->list, &nfsi->open_files); if (ctx->mode & FMODE_WRITE)
list_add(&ctx->list, &nfsi->open_files);
else
list_add_tail(&ctx->list, &nfsi->open_files);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
...@@ -972,6 +973,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) ...@@ -972,6 +973,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
if (NFS_STALE(inode)) if (NFS_STALE(inode))
goto out; goto out;
/* pNFS: Attributes aren't updated until we layoutcommit */
if (S_ISREG(inode->i_mode)) {
status = pnfs_sync_inode(inode, false);
if (status)
goto out;
}
status = -ENOMEM; status = -ENOMEM;
fattr = nfs_alloc_fattr(); fattr = nfs_alloc_fattr();
if (fattr == NULL) if (fattr == NULL)
...@@ -1122,14 +1130,12 @@ int nfs_revalidate_mapping_rcu(struct inode *inode) ...@@ -1122,14 +1130,12 @@ int nfs_revalidate_mapping_rcu(struct inode *inode)
} }
/** /**
* __nfs_revalidate_mapping - Revalidate the pagecache * nfs_revalidate_mapping - Revalidate the pagecache
* @inode - pointer to host inode * @inode - pointer to host inode
* @mapping - pointer to mapping * @mapping - pointer to mapping
* @may_lock - take inode->i_mutex?
*/ */
static int __nfs_revalidate_mapping(struct inode *inode, int nfs_revalidate_mapping(struct inode *inode,
struct address_space *mapping, struct address_space *mapping)
bool may_lock)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
unsigned long *bitlock = &nfsi->flags; unsigned long *bitlock = &nfsi->flags;
...@@ -1178,12 +1184,7 @@ static int __nfs_revalidate_mapping(struct inode *inode, ...@@ -1178,12 +1184,7 @@ static int __nfs_revalidate_mapping(struct inode *inode,
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
trace_nfs_invalidate_mapping_enter(inode); trace_nfs_invalidate_mapping_enter(inode);
if (may_lock) { ret = nfs_invalidate_mapping(inode, mapping);
inode_lock(inode);
ret = nfs_invalidate_mapping(inode, mapping);
inode_unlock(inode);
} else
ret = nfs_invalidate_mapping(inode, mapping);
trace_nfs_invalidate_mapping_exit(inode, ret); trace_nfs_invalidate_mapping_exit(inode, ret);
clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
...@@ -1193,27 +1194,28 @@ static int __nfs_revalidate_mapping(struct inode *inode, ...@@ -1193,27 +1194,28 @@ static int __nfs_revalidate_mapping(struct inode *inode,
return ret; return ret;
} }
/** static bool nfs_file_has_writers(struct nfs_inode *nfsi)
* nfs_revalidate_mapping - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*/
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{ {
return __nfs_revalidate_mapping(inode, mapping, false); struct inode *inode = &nfsi->vfs_inode;
assert_spin_locked(&inode->i_lock);
if (!S_ISREG(inode->i_mode))
return false;
if (list_empty(&nfsi->open_files))
return false;
/* Note: This relies on nfsi->open_files being ordered with writers
* being placed at the head of the list.
* See nfs_inode_attach_open_context()
*/
return (list_first_entry(&nfsi->open_files,
struct nfs_open_context,
list)->mode & FMODE_WRITE) == FMODE_WRITE;
} }
/** static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
* nfs_revalidate_mapping_protected - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*
* Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
* while invalidating the mapping.
*/
int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
{ {
return __nfs_revalidate_mapping(inode, mapping, true); return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi);
} }
static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
...@@ -1280,22 +1282,24 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1280,22 +1282,24 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
return -EIO; return -EIO;
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && if (!nfs_file_has_buffered_writers(nfsi)) {
inode->i_version != fattr->change_attr) /* Verify a few of the more important attributes */
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && inode->i_version != fattr->change_attr)
invalid |= NFS_INO_INVALID_ATTR | NFS_INO_REVAL_PAGECACHE;
/* Verify a few of the more important attributes */ if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime)) invalid |= NFS_INO_INVALID_ATTR;
invalid |= NFS_INO_INVALID_ATTR;
if (fattr->valid & NFS_ATTR_FATTR_SIZE) { if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec_equal(&inode->i_ctime, &fattr->ctime))
cur_size = i_size_read(inode); invalid |= NFS_INO_INVALID_ATTR;
new_isize = nfs_size_to_loff_t(fattr->size);
if (cur_size != new_isize) if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size);
if (cur_size != new_isize)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
}
} }
if (nfsi->nrequests != 0)
invalid &= ~NFS_INO_REVAL_PAGECACHE;
/* Have any file permissions changed? */ /* Have any file permissions changed? */
if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
...@@ -1470,28 +1474,12 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n ...@@ -1470,28 +1474,12 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
} }
/*
* Don't trust the change_attribute, mtime, ctime or size if
* a pnfs LAYOUTCOMMIT is outstanding
*/
static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
struct nfs_fattr *fattr)
{
if (pnfs_layoutcommit_outstanding(inode))
fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
NFS_ATTR_FATTR_MTIME |
NFS_ATTR_FATTR_CTIME |
NFS_ATTR_FATTR_SIZE);
}
static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{ {
int ret; int ret;
trace_nfs_refresh_inode_enter(inode); trace_nfs_refresh_inode_enter(inode);
nfs_inode_attrs_handle_layoutcommit(inode, fattr);
if (nfs_inode_attrs_need_update(inode, fattr)) if (nfs_inode_attrs_need_update(inode, fattr))
ret = nfs_update_inode(inode, fattr); ret = nfs_update_inode(inode, fattr);
else else
...@@ -1527,7 +1515,7 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode); ...@@ -1527,7 +1515,7 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode);
static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr) static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{ {
unsigned long invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; unsigned long invalid = NFS_INO_INVALID_ATTR;
/* /*
* Don't revalidate the pagecache if we hold a delegation, but do * Don't revalidate the pagecache if we hold a delegation, but do
...@@ -1676,7 +1664,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1676,7 +1664,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
unsigned long invalid = 0; unsigned long invalid = 0;
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned long save_cache_validity; unsigned long save_cache_validity;
bool cache_revalidated = true; bool have_writers = nfs_file_has_buffered_writers(nfsi);
bool cache_revalidated;
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
__func__, inode->i_sb->s_id, inode->i_ino, __func__, inode->i_sb->s_id, inode->i_ino,
...@@ -1725,17 +1714,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1725,17 +1714,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Do atomic weak cache consistency updates */ /* Do atomic weak cache consistency updates */
invalid |= nfs_wcc_update_inode(inode, fattr); invalid |= nfs_wcc_update_inode(inode, fattr);
cache_revalidated = !pnfs_layoutcommit_outstanding(inode);
/* More cache consistency checks */ /* More cache consistency checks */
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
if (inode->i_version != fattr->change_attr) { if (inode->i_version != fattr->change_attr) {
dprintk("NFS: change_attr change on server for file %s/%ld\n", dprintk("NFS: change_attr change on server for file %s/%ld\n",
inode->i_sb->s_id, inode->i_ino); inode->i_sb->s_id, inode->i_ino);
invalid |= NFS_INO_INVALID_ATTR /* Could it be a race with writeback? */
| NFS_INO_INVALID_DATA if (!have_writers) {
| NFS_INO_INVALID_ACCESS invalid |= NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACL; | NFS_INO_INVALID_DATA
if (S_ISDIR(inode->i_mode)) | NFS_INO_INVALID_ACCESS
nfs_force_lookup_revalidate(inode); | NFS_INO_INVALID_ACL;
if (S_ISDIR(inode->i_mode))
nfs_force_lookup_revalidate(inode);
}
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
} }
} else { } else {
...@@ -1768,9 +1763,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1768,9 +1763,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (new_isize != cur_isize) { if (new_isize != cur_isize) {
/* Do we perhaps have any outstanding writes, or has /* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */ * the file grown beyond our last write? */
if ((nfsi->nrequests == 0) || new_isize > cur_isize) { if (nfsi->nrequests == 0 || new_isize > cur_isize) {
i_size_write(inode, new_isize); i_size_write(inode, new_isize);
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; if (!have_writers)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
} }
dprintk("NFS: isize change on server for file %s/%ld " dprintk("NFS: isize change on server for file %s/%ld "
"(%Ld to %Ld)\n", "(%Ld to %Ld)\n",
......
...@@ -412,6 +412,19 @@ extern void __exit unregister_nfs_fs(void); ...@@ -412,6 +412,19 @@ extern void __exit unregister_nfs_fs(void);
extern bool nfs_sb_active(struct super_block *sb); extern bool nfs_sb_active(struct super_block *sb);
extern void nfs_sb_deactive(struct super_block *sb); extern void nfs_sb_deactive(struct super_block *sb);
/* io.c */
extern void nfs_start_io_read(struct inode *inode);
extern void nfs_end_io_read(struct inode *inode);
extern void nfs_start_io_write(struct inode *inode);
extern void nfs_end_io_write(struct inode *inode);
extern void nfs_start_io_direct(struct inode *inode);
extern void nfs_end_io_direct(struct inode *inode);
static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
{
return test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0;
}
/* namespace.c */ /* namespace.c */
#define NFS_PATH_CANONICAL 1 #define NFS_PATH_CANONICAL 1
extern char *nfs_path(char **p, struct dentry *dentry, extern char *nfs_path(char **p, struct dentry *dentry,
...@@ -500,6 +513,26 @@ int nfs_key_timeout_notify(struct file *filp, struct inode *inode); ...@@ -500,6 +513,26 @@ int nfs_key_timeout_notify(struct file *filp, struct inode *inode);
bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode); bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode);
void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio); void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio);
int nfs_filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend);
#ifdef CONFIG_NFS_V4_1
static inline
void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo)
{
int i;
for (i = 0; i < cinfo->nbuckets; i++)
cinfo->buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW;
}
#else
static inline
void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo)
{
}
#endif
#ifdef CONFIG_MIGRATION #ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *, extern int nfs_migrate_page(struct address_space *,
struct page *, struct page *, enum migrate_mode); struct page *, struct page *, enum migrate_mode);
...@@ -507,6 +540,13 @@ extern int nfs_migrate_page(struct address_space *, ...@@ -507,6 +540,13 @@ extern int nfs_migrate_page(struct address_space *,
#define nfs_migrate_page NULL #define nfs_migrate_page NULL
#endif #endif
static inline int
nfs_write_verifier_cmp(const struct nfs_write_verifier *v1,
const struct nfs_write_verifier *v2)
{
return memcmp(v1->data, v2->data, sizeof(v1->data));
}
/* unlink.c */ /* unlink.c */
extern struct rpc_task * extern struct rpc_task *
nfs_async_rename(struct inode *old_dir, struct inode *new_dir, nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
......
/*
* Copyright (c) 2016 Trond Myklebust
*
* I/O and data path helper functionality.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/rwsem.h>
#include <linux/fs.h>
#include <linux/nfs_fs.h>
#include "internal.h"
/* Call with exclusively locked inode->i_rwsem */
static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
{
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
inode_dio_wait(inode);
}
}
/**
* nfs_start_io_read - declare the file is being used for buffered reads
* @inode - file inode
*
* Declare that a buffered read operation is about to start, and ensure
* that we block all direct I/O.
* On exit, the function ensures that the NFS_INO_ODIRECT flag is unset,
* and holds a shared lock on inode->i_rwsem to ensure that the flag
* cannot be changed.
* In practice, this means that buffered read operations are allowed to
* execute in parallel, thanks to the shared lock, whereas direct I/O
* operations need to wait to grab an exclusive lock in order to set
* NFS_INO_ODIRECT.
* Note that buffered writes and truncates both take a write lock on
* inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
*/
void
nfs_start_io_read(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
/* Be an optimist! */
down_read(&inode->i_rwsem);
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0)
return;
up_read(&inode->i_rwsem);
/* Slow path.... */
down_write(&inode->i_rwsem);
nfs_block_o_direct(nfsi, inode);
downgrade_write(&inode->i_rwsem);
}
/**
* nfs_end_io_read - declare that the buffered read operation is done
* @inode - file inode
*
* Declare that a buffered read operation is done, and release the shared
* lock on inode->i_rwsem.
*/
void
nfs_end_io_read(struct inode *inode)
{
up_read(&inode->i_rwsem);
}
/**
* nfs_start_io_write - declare the file is being used for buffered writes
* @inode - file inode
*
* Declare that a buffered read operation is about to start, and ensure
* that we block all direct I/O.
*/
void
nfs_start_io_write(struct inode *inode)
{
down_write(&inode->i_rwsem);
nfs_block_o_direct(NFS_I(inode), inode);
}
/**
* nfs_end_io_write - declare that the buffered write operation is done
* @inode - file inode
*
* Declare that a buffered write operation is done, and release the
* lock on inode->i_rwsem.
*/
void
nfs_end_io_write(struct inode *inode)
{
up_write(&inode->i_rwsem);
}
/* Call with exclusively locked inode->i_rwsem */
static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode)
{
if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
set_bit(NFS_INO_ODIRECT, &nfsi->flags);
nfs_wb_all(inode);
}
}
/**
* nfs_end_io_direct - declare the file is being used for direct i/o
* @inode - file inode
*
* Declare that a direct I/O operation is about to start, and ensure
* that we block all buffered I/O.
* On exit, the function ensures that the NFS_INO_ODIRECT flag is set,
* and holds a shared lock on inode->i_rwsem to ensure that the flag
* cannot be changed.
* In practice, this means that direct I/O operations are allowed to
* execute in parallel, thanks to the shared lock, whereas buffered I/O
* operations need to wait to grab an exclusive lock in order to clear
* NFS_INO_ODIRECT.
* Note that buffered writes and truncates both take a write lock on
* inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
*/
void
nfs_start_io_direct(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
/* Be an optimist! */
down_read(&inode->i_rwsem);
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) != 0)
return;
up_read(&inode->i_rwsem);
/* Slow path.... */
down_write(&inode->i_rwsem);
nfs_block_buffered(nfsi, inode);
downgrade_write(&inode->i_rwsem);
}
/**
* nfs_end_io_direct - declare that the direct i/o operation is done
* @inode - file inode
*
* Declare that a direct I/O operation is done, and release the shared
* lock on inode->i_rwsem.
*/
void
nfs_end_io_direct(struct inode *inode)
{
up_read(&inode->i_rwsem);
}
...@@ -113,15 +113,17 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) ...@@ -113,15 +113,17 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
return -EOPNOTSUPP; return -EOPNOTSUPP;
nfs_wb_all(inode);
inode_lock(inode); inode_lock(inode);
err = nfs_sync_inode(inode);
if (err)
goto out_unlock;
err = nfs42_proc_fallocate(&msg, filep, offset, len); err = nfs42_proc_fallocate(&msg, filep, offset, len);
if (err == 0) if (err == 0)
truncate_pagecache_range(inode, offset, (offset + len) -1); truncate_pagecache_range(inode, offset, (offset + len) -1);
if (err == -EOPNOTSUPP) if (err == -EOPNOTSUPP)
NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE; NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
out_unlock:
inode_unlock(inode); inode_unlock(inode);
return err; return err;
} }
...@@ -154,11 +156,20 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -154,11 +156,20 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
if (status) if (status)
return status; return status;
status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
pos_src, pos_src + (loff_t)count - 1);
if (status)
return status;
status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
dst_lock, FMODE_WRITE); dst_lock, FMODE_WRITE);
if (status) if (status)
return status; return status;
status = nfs_sync_inode(dst_inode);
if (status)
return status;
status = nfs4_call_sync(server->client, server, &msg, status = nfs4_call_sync(server->client, server, &msg,
&args.seq_args, &res.seq_res, 0); &args.seq_args, &res.seq_res, 0);
if (status == -ENOTSUPP) if (status == -ENOTSUPP)
...@@ -258,7 +269,11 @@ static loff_t _nfs42_proc_llseek(struct file *filep, ...@@ -258,7 +269,11 @@ static loff_t _nfs42_proc_llseek(struct file *filep,
if (status) if (status)
return status; return status;
nfs_wb_all(inode); status = nfs_filemap_write_and_wait_range(inode->i_mapping,
offset, LLONG_MAX);
if (status)
return status;
status = nfs4_call_sync(server->client, server, &msg, status = nfs4_call_sync(server->client, server, &msg,
&args.seq_args, &res.seq_res, 0); &args.seq_args, &res.seq_res, 0);
if (status == -ENOTSUPP) if (status == -ENOTSUPP)
......
...@@ -66,7 +66,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) ...@@ -66,7 +66,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
if (openflags & O_TRUNC) { if (openflags & O_TRUNC) {
attr.ia_valid |= ATTR_SIZE; attr.ia_valid |= ATTR_SIZE;
attr.ia_size = 0; attr.ia_size = 0;
nfs_sync_inode(inode); filemap_write_and_wait(inode->i_mapping);
} }
inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL); inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL);
...@@ -133,21 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -133,21 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out, struct file *file_out, loff_t pos_out,
size_t count, unsigned int flags) size_t count, unsigned int flags)
{ {
struct inode *in_inode = file_inode(file_in); if (file_inode(file_in) == file_inode(file_out))
struct inode *out_inode = file_inode(file_out);
int ret;
if (in_inode == out_inode)
return -EINVAL; return -EINVAL;
/* flush any pending writes */
ret = nfs_sync_inode(in_inode);
if (ret)
return ret;
ret = nfs_sync_inode(out_inode);
if (ret)
return ret;
return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
} }
......
...@@ -1985,9 +1985,14 @@ encode_layoutcommit(struct xdr_stream *xdr, ...@@ -1985,9 +1985,14 @@ encode_layoutcommit(struct xdr_stream *xdr,
p = xdr_encode_hyper(p, args->lastbytewritten + 1); /* length */ p = xdr_encode_hyper(p, args->lastbytewritten + 1); /* length */
*p = cpu_to_be32(0); /* reclaim */ *p = cpu_to_be32(0); /* reclaim */
encode_nfs4_stateid(xdr, &args->stateid); encode_nfs4_stateid(xdr, &args->stateid);
p = reserve_space(xdr, 20); if (args->lastbytewritten != U64_MAX) {
*p++ = cpu_to_be32(1); /* newoffset = TRUE */ p = reserve_space(xdr, 20);
p = xdr_encode_hyper(p, args->lastbytewritten); *p++ = cpu_to_be32(1); /* newoffset = TRUE */
p = xdr_encode_hyper(p, args->lastbytewritten);
} else {
p = reserve_space(xdr, 12);
*p++ = cpu_to_be32(0); /* newoffset = FALSE */
}
*p++ = cpu_to_be32(0); /* Never send time_modify_changed */ *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
*p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */ *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
{ 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \ { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
{ 1 << NFS_INO_STALE, "STALE" }, \ { 1 << NFS_INO_STALE, "STALE" }, \
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
{ 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
......
...@@ -2393,7 +2393,10 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -2393,7 +2393,10 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
nfs_fattr_init(&data->fattr); nfs_fattr_init(&data->fattr);
data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
data->res.fattr = &data->fattr; data->res.fattr = &data->fattr;
data->args.lastbytewritten = end_pos - 1; if (end_pos != 0)
data->args.lastbytewritten = end_pos - 1;
else
data->args.lastbytewritten = U64_MAX;
data->res.server = NFS_SERVER(inode); data->res.server = NFS_SERVER(inode);
if (ld->prepare_layoutcommit) { if (ld->prepare_layoutcommit) {
......
...@@ -628,6 +628,13 @@ pnfs_sync_inode(struct inode *inode, bool datasync) ...@@ -628,6 +628,13 @@ pnfs_sync_inode(struct inode *inode, bool datasync)
return 0; return 0;
} }
static inline bool
pnfs_layoutcommit_outstanding(struct inode *inode)
{
return false;
}
static inline bool static inline bool
pnfs_roc(struct inode *ino) pnfs_roc(struct inode *ino)
{ {
...@@ -716,13 +723,6 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src, ...@@ -716,13 +723,6 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src,
return false; return false;
} }
static inline bool
pnfs_layoutcommit_outstanding(struct inode *inode)
{
return false;
}
static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void) static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
{ {
return NULL; return NULL;
......
...@@ -940,6 +940,13 @@ EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit); ...@@ -940,6 +940,13 @@ EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
int int
pnfs_nfs_generic_sync(struct inode *inode, bool datasync) pnfs_nfs_generic_sync(struct inode *inode, bool datasync)
{ {
int ret;
if (!pnfs_layoutcommit_outstanding(inode))
return 0;
ret = nfs_commit_inode(inode, FLUSH_SYNC);
if (ret < 0)
return ret;
if (datasync) if (datasync)
return 0; return 0;
return pnfs_layoutcommit_inode(inode, true); return pnfs_layoutcommit_inode(inode, true);
......
...@@ -625,7 +625,7 @@ static int nfs_writepage_locked(struct page *page, ...@@ -625,7 +625,7 @@ static int nfs_writepage_locked(struct page *page,
int err; int err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), nfs_pageio_init_write(&pgio, inode, 0,
false, &nfs_async_write_completion_ops); false, &nfs_async_write_completion_ops);
err = nfs_do_writepage(page, wbc, &pgio, launder); err = nfs_do_writepage(page, wbc, &pgio, launder);
nfs_pageio_complete(&pgio); nfs_pageio_complete(&pgio);
...@@ -657,16 +657,9 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * ...@@ -657,16 +657,9 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
unsigned long *bitlock = &NFS_I(inode)->flags;
struct nfs_pageio_descriptor pgio; struct nfs_pageio_descriptor pgio;
int err; int err;
/* Stop dirtying of new pages while we sync */
err = wait_on_bit_lock_action(bitlock, NFS_INO_FLUSHING,
nfs_wait_bit_killable, TASK_KILLABLE);
if (err)
goto out_err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false, nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false,
...@@ -674,10 +667,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) ...@@ -674,10 +667,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
nfs_pageio_complete(&pgio); nfs_pageio_complete(&pgio);
clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
smp_mb__after_atomic();
wake_up_bit(bitlock, NFS_INO_FLUSHING);
if (err < 0) if (err < 0)
goto out_err; goto out_err;
err = pgio.pg_error; err = pgio.pg_error;
...@@ -1805,7 +1794,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) ...@@ -1805,7 +1794,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
/* Okay, COMMIT succeeded, apparently. Check the verifier /* Okay, COMMIT succeeded, apparently. Check the verifier
* returned by the server against all stored verfs. */ * returned by the server against all stored verfs. */
if (!memcmp(&req->wb_verf, &data->verf.verifier, sizeof(req->wb_verf))) { if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) {
/* We have a match */ /* We have a match */
nfs_inode_remove_request(req); nfs_inode_remove_request(req);
dprintk(" OK\n"); dprintk(" OK\n");
...@@ -1928,6 +1917,24 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -1928,6 +1917,24 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
} }
EXPORT_SYMBOL_GPL(nfs_write_inode); EXPORT_SYMBOL_GPL(nfs_write_inode);
/*
* Wrapper for filemap_write_and_wait_range()
*
* Needed for pNFS in order to ensure data becomes visible to the
* client.
*/
int nfs_filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend)
{
int ret;
ret = filemap_write_and_wait_range(mapping, lstart, lend);
if (ret == 0)
ret = pnfs_sync_inode(mapping->host, true);
return ret;
}
EXPORT_SYMBOL_GPL(nfs_filemap_write_and_wait_range);
/* /*
* flush the inode to disk. * flush the inode to disk.
*/ */
......
...@@ -205,12 +205,12 @@ struct nfs_inode { ...@@ -205,12 +205,12 @@ struct nfs_inode {
#define NFS_INO_STALE (1) /* possible stale inode */ #define NFS_INO_STALE (1) /* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
#define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
#define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */
static inline struct nfs_inode *NFS_I(const struct inode *inode) static inline struct nfs_inode *NFS_I(const struct inode *inode)
{ {
...@@ -351,7 +351,6 @@ extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *ino ...@@ -351,7 +351,6 @@ extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *ino
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_revalidate_mapping_rcu(struct inode *inode); extern int nfs_revalidate_mapping_rcu(struct inode *inode);
extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *); extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *); extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment