Skip to content

Commit

Permalink
NFS: remove nfs_inode radix tree
Browse files Browse the repository at this point in the history
The radix tree is only being used to compile lists of reqs needing commit.
It is simpler to just put the reqs directly into a list.

Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Fred Isaman authored and Trond Myklebust committed Mar 10, 2012
1 parent 9994b62 commit d6d6dc7
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 194 deletions.
2 changes: 1 addition & 1 deletion fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,7 @@ static void init_once(void *foo)
INIT_LIST_HEAD(&nfsi->open_files);
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
INIT_LIST_HEAD(&nfsi->commit_list);
nfsi->npages = 0;
nfsi->ncommit = 0;
atomic_set(&nfsi->silly_count, 1);
Expand Down
2 changes: 2 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_readdata_release(struct nfs_read_data *rdata);

/* write.c */
extern int nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
int max);
extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
struct list_head *head);
extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
Expand Down
109 changes: 88 additions & 21 deletions fs/nfs/nfs4filelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,14 +682,16 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
int size = (fl->stripe_type == STRIPE_SPARSE) ?
fl->dsaddr->ds_num : fl->dsaddr->stripe_count;

fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags);
fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags);
if (!fl->commit_buckets) {
filelayout_free_lseg(&fl->generic_hdr);
return NULL;
}
fl->number_of_buckets = size;
for (i = 0; i < size; i++)
INIT_LIST_HEAD(&fl->commit_buckets[i]);
for (i = 0; i < size; i++) {
INIT_LIST_HEAD(&fl->commit_buckets[i].written);
INIT_LIST_HEAD(&fl->commit_buckets[i].committing);
}
}
return &fl->generic_hdr;
}
Expand Down Expand Up @@ -767,11 +769,6 @@ static const struct nfs_pageio_ops filelayout_pg_write_ops = {
.pg_doio = pnfs_generic_pg_writepages,
};

static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
{
return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
}

static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
{
if (fl->stripe_type == STRIPE_SPARSE)
Expand All @@ -780,13 +777,39 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
return j;
}

struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
/* The generic layer is about to remove the req from the commit list.
* If this will make the bucket empty, it will need to put the lseg reference.
* Note inode lock is held, so we can't do the put here.
*/
static struct pnfs_layout_segment *
filelayout_remove_commit_req(struct nfs_page *req)
{
if (list_is_singular(&req->wb_list)) {
struct inode *inode = req->wb_context->dentry->d_inode;
struct pnfs_layout_segment *lseg;

/* From here we can find the bucket, but for the moment,
* since there is only one relevant lseg...
*/
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
if (lseg->pls_range.iomode == IOMODE_RW)
return lseg;
}
}
return NULL;
}

static struct list_head *
filelayout_choose_commit_list(struct nfs_page *req,
struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_segment *lseg = req->wb_commit_lseg;
struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
u32 i, j;
struct list_head *list;

if (fl->commit_through_mds)
return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;

/* Note that we are calling nfs4_fl_calc_j_index on each page
* that ends up being committed to a data server. An attractive
* alternative is to add a field to nfs_write_data and nfs_page
Expand All @@ -796,9 +819,14 @@ struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
j = nfs4_fl_calc_j_index(lseg,
(loff_t)req->wb_index << PAGE_CACHE_SHIFT);
i = select_bucket_index(fl, j);
list = &fl->commit_buckets[i];
list = &fl->commit_buckets[i].written;
if (list_empty(list)) {
/* Non-empty buckets hold a reference on the lseg */
/* Non-empty buckets hold a reference on the lseg. That ref
* is normally transferred to the COMMIT call and released
* there. It could also be released if the last req is pulled
* off due to a rewrite, in which case it will be done in
* filelayout_remove_commit_req
*/
get_lseg(lseg);
}
return list;
Expand Down Expand Up @@ -860,18 +888,56 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
/*
* This is only useful while we are using whole file layouts.
*/
static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
static struct pnfs_layout_segment *
find_only_write_lseg_locked(struct inode *inode)
{
struct pnfs_layout_segment *lseg, *rv = NULL;
struct pnfs_layout_segment *lseg;

spin_lock(&inode->i_lock);
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
if (lseg->pls_range.iomode == IOMODE_RW)
rv = get_lseg(lseg);
return get_lseg(lseg);
return NULL;
}

static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
{
struct pnfs_layout_segment *rv;

spin_lock(&inode->i_lock);
rv = find_only_write_lseg_locked(inode);
spin_unlock(&inode->i_lock);
return rv;
}

/* Move reqs from written to committing lists, returning count of number moved.
* Note called with i_lock held.
*/
static int filelayout_scan_commit_lists(struct inode *inode, int max)
{
struct pnfs_layout_segment *lseg;
struct nfs4_filelayout_segment *fl;
int i, rv = 0, cnt;

lseg = find_only_write_lseg_locked(inode);
if (!lseg)
return 0;
fl = FILELAYOUT_LSEG(lseg);
if (fl->commit_through_mds)
goto out_put;
for (i = 0; i < fl->number_of_buckets; i++) {
if (list_empty(&fl->commit_buckets[i].written))
continue;
cnt = nfs_scan_commit_list(&fl->commit_buckets[i].written,
&fl->commit_buckets[i].committing,
max);
max -= cnt;
rv += cnt;
}
out_put:
put_lseg(lseg);
return rv;
}

static int alloc_ds_commits(struct inode *inode, struct list_head *list)
{
struct pnfs_layout_segment *lseg;
Expand All @@ -886,7 +952,7 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list)
return 0;
fl = FILELAYOUT_LSEG(lseg);
for (i = 0; i < fl->number_of_buckets; i++) {
if (list_empty(&fl->commit_buckets[i]))
if (list_empty(&fl->commit_buckets[i].committing))
continue;
data = nfs_commitdata_alloc();
if (!data)
Expand All @@ -900,9 +966,9 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list)

out_bad:
for (j = i; j < fl->number_of_buckets; j++) {
if (list_empty(&fl->commit_buckets[i]))
if (list_empty(&fl->commit_buckets[i].committing))
continue;
nfs_retry_commit(&fl->commit_buckets[i], lseg);
nfs_retry_commit(&fl->commit_buckets[i].committing, lseg);
put_lseg(lseg); /* associated with emptying bucket */
}
put_lseg(lseg);
Expand Down Expand Up @@ -937,7 +1003,7 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
nfs_initiate_commit(data, NFS_CLIENT(inode),
data->mds_ops, how);
} else {
nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg);
nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg);
filelayout_initiate_commit(data, how);
}
}
Expand Down Expand Up @@ -967,8 +1033,9 @@ static struct pnfs_layoutdriver_type filelayout_type = {
.free_lseg = filelayout_free_lseg,
.pg_read_ops = &filelayout_pg_read_ops,
.pg_write_ops = &filelayout_pg_write_ops,
.mark_pnfs_commit = filelayout_mark_pnfs_commit,
.choose_commit_list = filelayout_choose_commit_list,
.remove_commit_req = filelayout_remove_commit_req,
.scan_commit_lists = filelayout_scan_commit_lists,
.commit_pagelist = filelayout_commit_pagelist,
.read_pagelist = filelayout_read_pagelist,
.write_pagelist = filelayout_write_pagelist,
Expand Down
7 changes: 6 additions & 1 deletion fs/nfs/nfs4filelayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ struct nfs4_file_layout_dsaddr {
struct nfs4_pnfs_ds *ds_list[1];
};

struct nfs4_fl_commit_bucket {
struct list_head written;
struct list_head committing;
};

struct nfs4_filelayout_segment {
struct pnfs_layout_segment generic_hdr;
u32 stripe_type;
Expand All @@ -84,7 +89,7 @@ struct nfs4_filelayout_segment {
struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
unsigned int num_fh;
struct nfs_fh **fh_array;
struct list_head *commit_buckets; /* Sort commits to ds */
struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
int number_of_buckets;
};

Expand Down
61 changes: 0 additions & 61 deletions fs/nfs/pagelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,67 +396,6 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
}
}

#define NFS_SCAN_MAXENTRIES 16
/**
* nfs_scan_list - Scan a list for matching requests
* @nfsi: NFS inode
* @dst: Destination list
* @idx_start: lower bound of page->index to scan
* @npages: idx_start + npages sets the upper bound to scan.
* @tag: tag to scan for
*
* Moves elements from one of the inode request lists.
* If the number of requests is set to 0, the entire address_space
* starting at index idx_start, is scanned.
* The requests are *not* checked to ensure that they form a contiguous set.
* You must be holding the inode's i_lock when calling this function
*/
int nfs_scan_list(struct nfs_inode *nfsi,
struct list_head *dst, pgoff_t idx_start,
unsigned int npages, int tag)
{
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
struct nfs_page *req;
pgoff_t idx_end;
int found, i;
int res;
struct list_head *list;

res = 0;
if (npages == 0)
idx_end = ~0;
else
idx_end = idx_start + npages - 1;

for (;;) {
found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
(void **)&pgvec[0], idx_start,
NFS_SCAN_MAXENTRIES, tag);
if (found <= 0)
break;
for (i = 0; i < found; i++) {
req = pgvec[i];
if (req->wb_index > idx_end)
goto out;
idx_start = req->wb_index + 1;
if (nfs_lock_request_dontget(req)) {
kref_get(&req->wb_kref);
radix_tree_tag_clear(&nfsi->nfs_page_tree,
req->wb_index, tag);
list = pnfs_choose_commit_list(req, dst);
nfs_list_add_request(req, list);
res++;
if (res == INT_MAX)
goto out;
}
}
/* for latency reduction */
cond_resched_lock(&nfsi->vfs_inode.i_lock);
}
out:
return res;
}

int __init nfs_init_nfspagecache(void)
{
nfs_page_cachep = kmem_cache_create("nfs_page",
Expand Down
Loading

0 comments on commit d6d6dc7

Please sign in to comment.