Skip to content

Commit

Permalink
Merge branch 'writeback'
Browse files Browse the repository at this point in the history
  • Loading branch information
Trond Myklebust committed Jul 24, 2016
2 parents 7f94ed2 + e033fb5 commit 3627452
Show file tree
Hide file tree
Showing 18 changed files with 438 additions and 282 deletions.
2 changes: 1 addition & 1 deletion fs/nfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o

CFLAGS_nfstrace.o += -I$(src)
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
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
Expand Down
52 changes: 31 additions & 21 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
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_access_entry *cache;
int err = -ENOENT;
bool retry = true;
int err;

spin_lock(&inode->i_lock);
if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
goto out_zap;
cache = nfs_access_search_rbtree(inode, cred);
if (cache == NULL)
goto out;
if (!nfs_have_delegated_attributes(inode) &&
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
goto out_stale;
for(;;) {
if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
goto out_zap;
cache = nfs_access_search_rbtree(inode, cred);
err = -ENOENT;
if (cache == NULL)
goto out;
/* 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->cred = cache->cred;
res->mask = cache->mask;
Expand All @@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
out:
spin_unlock(&inode->i_lock);
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:
spin_unlock(&inode->i_lock);
nfs_access_zap_cache(inode);
Expand All @@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
cache = NULL;
if (cache == NULL)
goto out;
if (!nfs_have_delegated_attributes(inode) &&
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode);
if (err)
goto out;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
res->mask = cache->mask;
err = 0;
out:
rcu_read_unlock();
return err;
Expand Down Expand Up @@ -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)
{
struct nfs_access_entry cache;
bool may_block = (mask & MAY_NOT_BLOCK) == 0;
int status;

trace_nfs_access_enter(inode);

status = nfs_access_get_cached_rcu(inode, cred, &cache);
if (status != 0)
status = nfs_access_get_cached(inode, cred, &cache);
status = nfs_access_get_cached(inode, cred, &cache, may_block);
if (status == 0)
goto out_cached;

status = -ECHILD;
if (mask & MAY_NOT_BLOCK)
if (!may_block)
goto out;

/* Be clever: ask server to check for all possible rights */
Expand Down
93 changes: 32 additions & 61 deletions fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
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
* @dreq - direct request possibly spanning multiple servers
Expand All @@ -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);
return 0;
}
return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
return nfs_direct_cmp_verf(verfp, &hdr->verf);
}

/*
Expand All @@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
if (verfp->committed < 0)
return 1;

return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
return nfs_direct_cmp_verf(verfp, &data->verf);
}

/**
Expand Down Expand Up @@ -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
* 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;

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);

if (dreq->iocb) {
Expand Down Expand Up @@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
}
out_put:
if (put_dreq(dreq))
nfs_direct_complete(dreq, false);
nfs_direct_complete(dreq);
hdr->release(hdr);
}

Expand Down Expand Up @@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
}

if (put_dreq(dreq))
nfs_direct_complete(dreq, false);
nfs_direct_complete(dreq);
return 0;
}

Expand Down Expand Up @@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (!count)
goto out;

inode_lock(inode);
result = nfs_sync_mapping(mapping);
if (result)
goto out_unlock;

task_io_account_read(count);

result = -ENOMEM;
dreq = nfs_direct_req_alloc();
if (dreq == NULL)
goto out_unlock;
goto out;

dreq->inode = inode;
dreq->bytes_left = dreq->max_count = count;
Expand All @@ -610,24 +599,21 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;

nfs_start_io_direct(inode);

NFS_I(inode)->read_io += count;
result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);

inode_unlock(inode);
nfs_end_io_direct(inode);

if (!result) {
result = nfs_direct_wait(dreq);
if (result > 0)
iocb->ki_pos += result;
}

nfs_direct_req_release(dreq);
return result;

out_release:
nfs_direct_req_release(dreq);
out_unlock:
inode_unlock(inode);
out:
return result;
}
Expand Down Expand Up @@ -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);

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++)
dreq->mirrors[i].count = 0;
get_dreq(dreq);
Expand Down Expand Up @@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
nfs_direct_write_reschedule(dreq);
break;
default:
nfs_direct_complete(dreq, true);
nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
nfs_direct_complete(dreq);
}
}

Expand Down Expand Up @@ -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 result = -EINVAL;
size_t count;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
Expand All @@ -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",
file, iov_iter_count(iter), (long long) iocb->ki_pos);

nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES,
iov_iter_count(iter));
result = generic_write_checks(iocb, iter);
if (result <= 0)
return result;
count = result;
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);

pos = iocb->ki_pos;
end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT;

inode_lock(inode);

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));
task_io_account_write(count);

result = -ENOMEM;
dreq = nfs_direct_req_alloc();
if (!dreq)
goto out_unlock;
goto out;

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->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx);
Expand All @@ -1042,37 +1022,28 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;

nfs_start_io_direct(inode);

result = nfs_direct_write_schedule_iovec(dreq, iter, pos);

if (mapping->nrpages) {
invalidate_inode_pages2_range(mapping,
pos >> PAGE_SHIFT, end);
}

inode_unlock(inode);
nfs_end_io_direct(inode);

if (!result) {
result = nfs_direct_wait(dreq);
if (result > 0) {
struct inode *inode = mapping->host;

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 */
generic_write_sync(iocb, result);
}
}
nfs_direct_req_release(dreq);
return result;

out_release:
nfs_direct_req_release(dreq);
out_unlock:
inode_unlock(inode);
out:
return result;
}

Expand Down
Loading

0 comments on commit 3627452

Please sign in to comment.