Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6d6dc7c authored by Fred Isaman's avatar Fred Isaman Committed by Trond Myklebust
Browse files

NFS: remove nfs_inode radix tree



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: default avatarFred Isaman <iisaman@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 9994b62b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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,
+88 −21
Original line number Diff line number Diff line
@@ -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;
}
@@ -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)
@@ -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
@@ -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;
@@ -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;
@@ -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)
@@ -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);
@@ -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);
		}
	}
@@ -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,
+6 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
};

+0 −61
Original line number Diff line number Diff line
@@ -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",
Loading