Linux Audio

Check our new training course

Loading...
  1/*
  2 * linux/fs/nfs/pagelist.c
  3 *
  4 * A set of helper functions for managing NFS read and write requests.
  5 * The main purpose of these routines is to provide support for the
  6 * coalescing of several requests into a single RPC call.
  7 *
  8 * Copyright 2000, 2001 (c) Trond Myklebust <trond.myklebust@fys.uio.no>
  9 *
 10 */
 11
 12#include <linux/slab.h>
 13#include <linux/file.h>
 14#include <linux/sched.h>
 15#include <linux/sunrpc/clnt.h>
 16#include <linux/nfs.h>
 17#include <linux/nfs3.h>
 18#include <linux/nfs4.h>
 19#include <linux/nfs_page.h>
 20#include <linux/nfs_fs.h>
 21#include <linux/nfs_mount.h>
 22#include <linux/export.h>
 23
 24#include "internal.h"
 25#include "pnfs.h"
 26
 27static struct kmem_cache *nfs_page_cachep;
 28
 29bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount)
 30{
 31	p->npages = pagecount;
 32	if (pagecount <= ARRAY_SIZE(p->page_array))
 33		p->pagevec = p->page_array;
 34	else {
 35		p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
 36		if (!p->pagevec)
 37			p->npages = 0;
 38	}
 39	return p->pagevec != NULL;
 40}
 41
 42void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
 43		       struct nfs_pgio_header *hdr,
 44		       void (*release)(struct nfs_pgio_header *hdr))
 45{
 46	hdr->req = nfs_list_entry(desc->pg_list.next);
 47	hdr->inode = desc->pg_inode;
 48	hdr->cred = hdr->req->wb_context->cred;
 49	hdr->io_start = req_offset(hdr->req);
 50	hdr->good_bytes = desc->pg_count;
 51	hdr->dreq = desc->pg_dreq;
 52	hdr->release = release;
 53	hdr->completion_ops = desc->pg_completion_ops;
 54	if (hdr->completion_ops->init_hdr)
 55		hdr->completion_ops->init_hdr(hdr);
 56}
 57
 58void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
 59{
 60	spin_lock(&hdr->lock);
 61	if (pos < hdr->io_start + hdr->good_bytes) {
 62		set_bit(NFS_IOHDR_ERROR, &hdr->flags);
 63		clear_bit(NFS_IOHDR_EOF, &hdr->flags);
 64		hdr->good_bytes = pos - hdr->io_start;
 65		hdr->error = error;
 66	}
 67	spin_unlock(&hdr->lock);
 68}
 69
 70static inline struct nfs_page *
 71nfs_page_alloc(void)
 72{
 73	struct nfs_page	*p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL);
 74	if (p)
 75		INIT_LIST_HEAD(&p->wb_list);
 76	return p;
 77}
 78
 79static inline void
 80nfs_page_free(struct nfs_page *p)
 81{
 82	kmem_cache_free(nfs_page_cachep, p);
 83}
 84
 85/**
 86 * nfs_create_request - Create an NFS read/write request.
 87 * @ctx: open context to use
 88 * @inode: inode to which the request is attached
 89 * @page: page to write
 90 * @offset: starting offset within the page for the write
 91 * @count: number of bytes to read/write
 92 *
 93 * The page must be locked by the caller. This makes sure we never
 94 * create two different requests for the same page.
 95 * User should ensure it is safe to sleep in this function.
 96 */
 97struct nfs_page *
 98nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
 99		   struct page *page,
100		   unsigned int offset, unsigned int count)
101{
102	struct nfs_page		*req;
103
104	/* try to allocate the request struct */
105	req = nfs_page_alloc();
106	if (req == NULL)
107		return ERR_PTR(-ENOMEM);
108
109	/* get lock context early so we can deal with alloc failures */
110	req->wb_lock_context = nfs_get_lock_context(ctx);
111	if (req->wb_lock_context == NULL) {
112		nfs_page_free(req);
113		return ERR_PTR(-ENOMEM);
114	}
115
116	/* Initialize the request struct. Initially, we assume a
117	 * long write-back delay. This will be adjusted in
118	 * update_nfs_request below if the region is not locked. */
119	req->wb_page    = page;
120	req->wb_index	= page->index;
121	page_cache_get(page);
122	req->wb_offset  = offset;
123	req->wb_pgbase	= offset;
124	req->wb_bytes   = count;
125	req->wb_context = get_nfs_open_context(ctx);
126	kref_init(&req->wb_kref);
127	return req;
128}
129
130/**
131 * nfs_unlock_request - Unlock request and wake up sleepers.
132 * @req:
133 */
134void nfs_unlock_request(struct nfs_page *req)
135{
136	if (!NFS_WBACK_BUSY(req)) {
137		printk(KERN_ERR "NFS: Invalid unlock attempted\n");
138		BUG();
139	}
140	smp_mb__before_clear_bit();
141	clear_bit(PG_BUSY, &req->wb_flags);
142	smp_mb__after_clear_bit();
143	wake_up_bit(&req->wb_flags, PG_BUSY);
144}
145
146/**
147 * nfs_unlock_and_release_request - Unlock request and release the nfs_page
148 * @req:
149 */
150void nfs_unlock_and_release_request(struct nfs_page *req)
151{
152	nfs_unlock_request(req);
153	nfs_release_request(req);
154}
155
156/*
157 * nfs_clear_request - Free up all resources allocated to the request
158 * @req:
159 *
160 * Release page and open context resources associated with a read/write
161 * request after it has completed.
162 */
163static void nfs_clear_request(struct nfs_page *req)
164{
165	struct page *page = req->wb_page;
166	struct nfs_open_context *ctx = req->wb_context;
167	struct nfs_lock_context *l_ctx = req->wb_lock_context;
168
169	if (page != NULL) {
170		page_cache_release(page);
171		req->wb_page = NULL;
172	}
173	if (l_ctx != NULL) {
174		nfs_put_lock_context(l_ctx);
175		req->wb_lock_context = NULL;
176	}
177	if (ctx != NULL) {
178		put_nfs_open_context(ctx);
179		req->wb_context = NULL;
180	}
181}
182
183
184/**
185 * nfs_release_request - Release the count on an NFS read/write request
186 * @req: request to release
187 *
188 * Note: Should never be called with the spinlock held!
189 */
190static void nfs_free_request(struct kref *kref)
191{
192	struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);
193
194	/* Release struct file and open context */
195	nfs_clear_request(req);
196	nfs_page_free(req);
197}
198
199void nfs_release_request(struct nfs_page *req)
200{
201	kref_put(&req->wb_kref, nfs_free_request);
202}
203
204static int nfs_wait_bit_uninterruptible(void *word)
205{
206	io_schedule();
207	return 0;
208}
209
210/**
211 * nfs_wait_on_request - Wait for a request to complete.
212 * @req: request to wait upon.
213 *
214 * Interruptible by fatal signals only.
215 * The user is responsible for holding a count on the request.
216 */
217int
218nfs_wait_on_request(struct nfs_page *req)
219{
220	return wait_on_bit(&req->wb_flags, PG_BUSY,
221			nfs_wait_bit_uninterruptible,
222			TASK_UNINTERRUPTIBLE);
223}
224
225bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_page *prev, struct nfs_page *req)
226{
227	/*
228	 * FIXME: ideally we should be able to coalesce all requests
229	 * that are not block boundary aligned, but currently this
230	 * is problematic for the case of bsize < PAGE_CACHE_SIZE,
231	 * since nfs_flush_multi and nfs_pagein_multi assume you
232	 * can have only one struct nfs_page.
233	 */
234	if (desc->pg_bsize < PAGE_SIZE)
235		return 0;
236
237	return desc->pg_count + req->wb_bytes <= desc->pg_bsize;
238}
239EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
240
241/**
242 * nfs_pageio_init - initialise a page io descriptor
243 * @desc: pointer to descriptor
244 * @inode: pointer to inode
245 * @doio: pointer to io function
246 * @bsize: io block size
247 * @io_flags: extra parameters for the io function
248 */
249void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
250		     struct inode *inode,
251		     const struct nfs_pageio_ops *pg_ops,
252		     const struct nfs_pgio_completion_ops *compl_ops,
253		     size_t bsize,
254		     int io_flags)
255{
256	INIT_LIST_HEAD(&desc->pg_list);
257	desc->pg_bytes_written = 0;
258	desc->pg_count = 0;
259	desc->pg_bsize = bsize;
260	desc->pg_base = 0;
261	desc->pg_moreio = 0;
262	desc->pg_recoalesce = 0;
263	desc->pg_inode = inode;
264	desc->pg_ops = pg_ops;
265	desc->pg_completion_ops = compl_ops;
266	desc->pg_ioflags = io_flags;
267	desc->pg_error = 0;
268	desc->pg_lseg = NULL;
269	desc->pg_dreq = NULL;
270}
271
272/**
273 * nfs_can_coalesce_requests - test two requests for compatibility
274 * @prev: pointer to nfs_page
275 * @req: pointer to nfs_page
276 *
277 * The nfs_page structures 'prev' and 'req' are compared to ensure that the
278 * page data area they describe is contiguous, and that their RPC
279 * credentials, NFSv4 open state, and lockowners are the same.
280 *
281 * Return 'true' if this is the case, else return 'false'.
282 */
283static bool nfs_can_coalesce_requests(struct nfs_page *prev,
284				      struct nfs_page *req,
285				      struct nfs_pageio_descriptor *pgio)
286{
287	if (req->wb_context->cred != prev->wb_context->cred)
288		return false;
289	if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner)
290		return false;
291	if (req->wb_context->state != prev->wb_context->state)
292		return false;
293	if (req->wb_pgbase != 0)
294		return false;
295	if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
296		return false;
297	if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
298		return false;
299	return pgio->pg_ops->pg_test(pgio, prev, req);
300}
301
302/**
303 * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list.
304 * @desc: destination io descriptor
305 * @req: request
306 *
307 * Returns true if the request 'req' was successfully coalesced into the
308 * existing list of pages 'desc'.
309 */
310static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
311				     struct nfs_page *req)
312{
313	if (desc->pg_count != 0) {
314		struct nfs_page *prev;
315
316		prev = nfs_list_entry(desc->pg_list.prev);
317		if (!nfs_can_coalesce_requests(prev, req, desc))
318			return 0;
319	} else {
320		if (desc->pg_ops->pg_init)
321			desc->pg_ops->pg_init(desc, req);
322		desc->pg_base = req->wb_pgbase;
323	}
324	nfs_list_remove_request(req);
325	nfs_list_add_request(req, &desc->pg_list);
326	desc->pg_count += req->wb_bytes;
327	return 1;
328}
329
330/*
331 * Helper for nfs_pageio_add_request and nfs_pageio_complete
332 */
333static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
334{
335	if (!list_empty(&desc->pg_list)) {
336		int error = desc->pg_ops->pg_doio(desc);
337		if (error < 0)
338			desc->pg_error = error;
339		else
340			desc->pg_bytes_written += desc->pg_count;
341	}
342	if (list_empty(&desc->pg_list)) {
343		desc->pg_count = 0;
344		desc->pg_base = 0;
345	}
346}
347
348/**
349 * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
350 * @desc: destination io descriptor
351 * @req: request
352 *
353 * Returns true if the request 'req' was successfully coalesced into the
354 * existing list of pages 'desc'.
355 */
356static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
357			   struct nfs_page *req)
358{
359	while (!nfs_pageio_do_add_request(desc, req)) {
360		desc->pg_moreio = 1;
361		nfs_pageio_doio(desc);
362		if (desc->pg_error < 0)
363			return 0;
364		desc->pg_moreio = 0;
365		if (desc->pg_recoalesce)
366			return 0;
367	}
368	return 1;
369}
370
371static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
372{
373	LIST_HEAD(head);
374
375	do {
376		list_splice_init(&desc->pg_list, &head);
377		desc->pg_bytes_written -= desc->pg_count;
378		desc->pg_count = 0;
379		desc->pg_base = 0;
380		desc->pg_recoalesce = 0;
381
382		while (!list_empty(&head)) {
383			struct nfs_page *req;
384
385			req = list_first_entry(&head, struct nfs_page, wb_list);
386			nfs_list_remove_request(req);
387			if (__nfs_pageio_add_request(desc, req))
388				continue;
389			if (desc->pg_error < 0)
390				return 0;
391			break;
392		}
393	} while (desc->pg_recoalesce);
394	return 1;
395}
396
397int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
398		struct nfs_page *req)
399{
400	int ret;
401
402	do {
403		ret = __nfs_pageio_add_request(desc, req);
404		if (ret)
405			break;
406		if (desc->pg_error < 0)
407			break;
408		ret = nfs_do_recoalesce(desc);
409	} while (ret);
410	return ret;
411}
412
413/**
414 * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
415 * @desc: pointer to io descriptor
416 */
417void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
418{
419	for (;;) {
420		nfs_pageio_doio(desc);
421		if (!desc->pg_recoalesce)
422			break;
423		if (!nfs_do_recoalesce(desc))
424			break;
425	}
426}
427
428/**
429 * nfs_pageio_cond_complete - Conditional I/O completion
430 * @desc: pointer to io descriptor
431 * @index: page index
432 *
433 * It is important to ensure that processes don't try to take locks
434 * on non-contiguous ranges of pages as that might deadlock. This
435 * function should be called before attempting to wait on a locked
436 * nfs_page. It will complete the I/O if the page index 'index'
437 * is not contiguous with the existing list of pages in 'desc'.
438 */
439void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
440{
441	if (!list_empty(&desc->pg_list)) {
442		struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
443		if (index != prev->wb_index + 1)
444			nfs_pageio_complete(desc);
445	}
446}
447
448int __init nfs_init_nfspagecache(void)
449{
450	nfs_page_cachep = kmem_cache_create("nfs_page",
451					    sizeof(struct nfs_page),
452					    0, SLAB_HWCACHE_ALIGN,
453					    NULL);
454	if (nfs_page_cachep == NULL)
455		return -ENOMEM;
456
457	return 0;
458}
459
460void nfs_destroy_nfspagecache(void)
461{
462	kmem_cache_destroy(nfs_page_cachep);
463}
464