pagelist.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. #include <linux/config.h>
  12. #include <linux/slab.h>
  13. #include <linux/file.h>
  14. #include <linux/sunrpc/clnt.h>
  15. #include <linux/nfs3.h>
  16. #include <linux/nfs_page.h>
  17. #include <linux/nfs_fs.h>
  18. #include <linux/nfs_flushd.h>
  19. #include <linux/nfs_mount.h>
  20. #define NFS_PARANOIA 1
  21. /*
  22.  * Spinlock
  23.  */
  24. spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED;
  25. static kmem_cache_t *nfs_page_cachep;
  26. static inline struct nfs_page *
  27. nfs_page_alloc(void)
  28. {
  29. struct nfs_page *p;
  30. p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
  31. if (p) {
  32. memset(p, 0, sizeof(*p));
  33. INIT_LIST_HEAD(&p->wb_hash);
  34. INIT_LIST_HEAD(&p->wb_list);
  35. INIT_LIST_HEAD(&p->wb_lru);
  36. init_waitqueue_head(&p->wb_wait);
  37. }
  38. return p;
  39. }
  40. static inline void
  41. nfs_page_free(struct nfs_page *p)
  42. {
  43. kmem_cache_free(nfs_page_cachep, p);
  44. }
  45. static int nfs_try_to_free_pages(struct nfs_server *);
  46. /**
  47.  * nfs_create_request - Create an NFS read/write request.
  48.  * @cred: RPC credential to use
  49.  * @inode: inode to which the request is attached
  50.  * @page: page to write
  51.  * @offset: starting offset within the page for the write
  52.  * @count: number of bytes to read/write
  53.  *
  54.  * The page must be locked by the caller. This makes sure we never
  55.  * create two different requests for the same page, and avoids
  56.  * a possible deadlock when we reach the hard limit on the number
  57.  * of dirty pages.
  58.  * User should ensure it is safe to sleep in this function.
  59.  */
  60. struct nfs_page *
  61. nfs_create_request(struct rpc_cred *cred, struct inode *inode,
  62.    struct page *page,
  63.    unsigned int offset, unsigned int count)
  64. {
  65. struct nfs_server *server = NFS_SERVER(inode);
  66. struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
  67. struct nfs_page *req;
  68. /* Deal with hard limits.  */
  69. for (;;) {
  70. /* Prevent races by incrementing *before* we test */
  71. atomic_inc(&cache->nr_requests);
  72. /* If we haven't reached the local hard limit yet,
  73.  * try to allocate the request struct */
  74. if (atomic_read(&cache->nr_requests) <= MAX_REQUEST_HARD) {
  75. req = nfs_page_alloc();
  76. if (req != NULL)
  77. break;
  78. }
  79. atomic_dec(&cache->nr_requests);
  80. /* Try to free up at least one request in order to stay
  81.  * below the hard limit
  82.  */
  83. if (nfs_try_to_free_pages(server))
  84. continue;
  85. if (signalled() && (server->flags & NFS_MOUNT_INTR))
  86. return ERR_PTR(-ERESTARTSYS);
  87. yield();
  88. }
  89. /* Initialize the request struct. Initially, we assume a
  90.  * long write-back delay. This will be adjusted in
  91.  * update_nfs_request below if the region is not locked. */
  92. req->wb_page    = page;
  93. page_cache_get(page);
  94. req->wb_offset  = offset;
  95. req->wb_bytes   = count;
  96. if (cred)
  97. req->wb_cred = get_rpccred(cred);
  98. req->wb_inode   = inode;
  99. req->wb_count   = 1;
  100. return req;
  101. }
  102. /**
  103.  * nfs_clear_request - Free up all resources allocated to the request
  104.  * @req:
  105.  *
  106.  * Release all resources associated with a write request after it
  107.  * has completed.
  108.  */
  109. void nfs_clear_request(struct nfs_page *req)
  110. {
  111. /* Release struct file or cached credential */
  112. if (req->wb_file) {
  113. fput(req->wb_file);
  114. req->wb_file = NULL;
  115. }
  116. if (req->wb_cred) {
  117. put_rpccred(req->wb_cred);
  118. req->wb_cred = NULL;
  119. }
  120. if (req->wb_page) {
  121. page_cache_release(req->wb_page);
  122. req->wb_page = NULL;
  123. atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
  124. }
  125. }
  126. /**
  127.  * nfs_release_request - Release the count on an NFS read/write request
  128.  * @req: request to release
  129.  *
  130.  * Note: Should never be called with the spinlock held!
  131.  */
  132. void
  133. nfs_release_request(struct nfs_page *req)
  134. {
  135. spin_lock(&nfs_wreq_lock);
  136. if (--req->wb_count) {
  137. spin_unlock(&nfs_wreq_lock);
  138. return;
  139. }
  140. __nfs_del_lru(req);
  141. spin_unlock(&nfs_wreq_lock);
  142. #ifdef NFS_PARANOIA
  143. if (!list_empty(&req->wb_list))
  144. BUG();
  145. if (!list_empty(&req->wb_hash))
  146. BUG();
  147. if (NFS_WBACK_BUSY(req))
  148. BUG();
  149. if (atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0)
  150. BUG();
  151. #endif
  152. /* Release struct file or cached credential */
  153. nfs_clear_request(req);
  154. nfs_page_free(req);
  155. }
  156. /**
  157.  * nfs_list_add_request - Insert a request into a sorted list
  158.  * @req: request
  159.  * @head: head of list into which to insert the request.
  160.  *
  161.  * Note that the wb_list is sorted by page index in order to facilitate
  162.  * coalescing of requests.
  163.  * We use an insertion sort that is optimized for the case of appended
  164.  * writes.
  165.  */
  166. void
  167. nfs_list_add_request(struct nfs_page *req, struct list_head *head)
  168. {
  169. struct list_head *pos;
  170. unsigned long pg_idx = page_index(req->wb_page);
  171. #ifdef NFS_PARANOIA
  172. if (!list_empty(&req->wb_list)) {
  173. printk(KERN_ERR "NFS: Add to list failed!n");
  174. BUG();
  175. }
  176. #endif
  177. list_for_each_prev(pos, head) {
  178. struct nfs_page *p = nfs_list_entry(pos);
  179. if (page_index(p->wb_page) < pg_idx)
  180. break;
  181. }
  182. list_add(&req->wb_list, pos);
  183. req->wb_list_head = head;
  184. }
  185. /**
  186.  * nfs_wait_on_request - Wait for a request to complete.
  187.  * @req: request to wait upon.
  188.  *
  189.  * Interruptible by signals only if mounted with intr flag.
  190.  * The user is responsible for holding a count on the request.
  191.  */
  192. int
  193. nfs_wait_on_request(struct nfs_page *req)
  194. {
  195. struct inode *inode = req->wb_inode;
  196.         struct rpc_clnt *clnt = NFS_CLIENT(inode);
  197. if (!NFS_WBACK_BUSY(req))
  198. return 0;
  199. return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
  200. }
  201. /**
  202.  * nfs_coalesce_requests - Split coalesced requests out from a list.
  203.  * @head: source list
  204.  * @dst: destination list
  205.  * @nmax: maximum number of requests to coalesce
  206.  *
  207.  * Moves a maximum of 'nmax' elements from one list to another.
  208.  * The elements are checked to ensure that they form a contiguous set
  209.  * of pages, and that they originated from the same file.
  210.  */
  211. int
  212. nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
  213.       unsigned int nmax)
  214. {
  215. struct nfs_page *req = NULL;
  216. unsigned int npages = 0;
  217. while (!list_empty(head)) {
  218. struct nfs_page *prev = req;
  219. req = nfs_list_entry(head->next);
  220. if (prev) {
  221. if (req->wb_cred != prev->wb_cred)
  222. break;
  223. if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
  224. break;
  225. if (req->wb_offset != 0)
  226. break;
  227. }
  228. nfs_list_remove_request(req);
  229. nfs_list_add_request(req, dst);
  230. npages++;
  231. if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE)
  232. break;
  233. if (npages >= nmax)
  234. break;
  235. }
  236. return npages;
  237. }
  238. /*
  239.  * nfs_scan_forward - Coalesce more requests
  240.  * @req: First request to add
  241.  * @dst: destination list
  242.  * @nmax: maximum number of requests to coalesce
  243.  *
  244.  * Tries to coalesce more requests by traversing the request's wb_list.
  245.  * Moves the resulting list into dst. Requests are guaranteed to be
  246.  * contiguous, and to originate from the same file.
  247.  */
  248. static int
  249. nfs_scan_forward(struct nfs_page *req, struct list_head *dst, int nmax)
  250. {
  251. struct nfs_server *server = NFS_SERVER(req->wb_inode);
  252. struct list_head *pos, *head = req->wb_list_head;
  253. struct rpc_cred *cred = req->wb_cred;
  254. unsigned long idx = page_index(req->wb_page) + 1;
  255. int npages = 0;
  256. for (pos = req->wb_list.next; nfs_lock_request(req); pos = pos->next) {
  257. nfs_list_remove_request(req);
  258. nfs_list_add_request(req, dst);
  259. __nfs_del_lru(req);
  260. __nfs_add_lru(&server->lru_busy, req);
  261. npages++;
  262. if (npages == nmax)
  263. break;
  264. if (pos == head)
  265. break;
  266. if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE)
  267. break;
  268. req = nfs_list_entry(pos);
  269. if (page_index(req->wb_page) != idx++)
  270. break;
  271. if (req->wb_offset != 0)
  272. break;
  273. if (req->wb_cred != cred)
  274. break;
  275. }
  276. return npages;
  277. }
  278. /**
  279.  * nfs_scan_lru - Scan one of the least recently used list
  280.  * @head: One of the NFS superblock lru lists
  281.  * @dst: Destination list
  282.  * @nmax: maximum number of requests to coalesce
  283.  *
  284.  * Scans one of the NFS superblock lru lists for upto nmax requests
  285.  * and returns them on a list. The requests are all guaranteed to be
  286.  * contiguous, originating from the same inode and the same file.
  287.  */
  288. int
  289. nfs_scan_lru(struct list_head *head, struct list_head *dst, int nmax)
  290. {
  291. struct list_head *pos;
  292. struct nfs_page *req;
  293. int npages = 0;
  294. list_for_each(pos, head) {
  295. req = nfs_lru_entry(pos);
  296. npages = nfs_scan_forward(req, dst, nmax);
  297. if (npages)
  298. break;
  299. }
  300. return npages;
  301. }
  302. /**
  303.  * nfs_scan_lru_timeout - Scan one of the superblock lru lists for timed out requests
  304.  * @head: One of the NFS superblock lru lists
  305.  * @dst: Destination list
  306.  * @nmax: maximum number of requests to coalesce
  307.  *
  308.  * Scans one of the NFS superblock lru lists for upto nmax requests
  309.  * and returns them on a list. The requests are all guaranteed to be
  310.  * contiguous, originating from the same inode and the same file.
  311.  * The first request on the destination list will be timed out, the
  312.  * others are not guaranteed to be so.
  313.  */
  314. int
  315. nfs_scan_lru_timeout(struct list_head *head, struct list_head *dst, int nmax)
  316. {
  317. struct list_head *pos;
  318. struct nfs_page *req;
  319. int npages = 0;
  320. list_for_each(pos, head) {
  321. req = nfs_lru_entry(pos);
  322. if (time_after(req->wb_timeout, jiffies))
  323. break;
  324. npages = nfs_scan_forward(req, dst, nmax);
  325. if (npages)
  326. break;
  327. }
  328. return npages;
  329. }
  330. /**
  331.  * nfs_scan_list - Scan a list for matching requests
  332.  * @head: One of the NFS inode request lists
  333.  * @dst: Destination list
  334.  * @file: if set, ensure we match requests from this file
  335.  * @idx_start: lower bound of page->index to scan
  336.  * @npages: idx_start + npages sets the upper bound to scan.
  337.  *
  338.  * Moves elements from one of the inode request lists.
  339.  * If the number of requests is set to 0, the entire address_space
  340.  * starting at index idx_start, is scanned.
  341.  * The requests are *not* checked to ensure that they form a contiguous set.
  342.  * You must be holding the nfs_wreq_lock when calling this function
  343.  */
  344. int
  345. nfs_scan_list(struct list_head *head, struct list_head *dst,
  346.       struct file *file,
  347.       unsigned long idx_start, unsigned int npages)
  348. {
  349. struct list_head *pos, *tmp;
  350. struct nfs_page *req;
  351. unsigned long idx_end;
  352. int res;
  353. res = 0;
  354. if (npages == 0)
  355. idx_end = ~0;
  356. else
  357. idx_end = idx_start + npages - 1;
  358. list_for_each_safe(pos, tmp, head) {
  359. unsigned long pg_idx;
  360. req = nfs_list_entry(pos);
  361. if (file && req->wb_file != file)
  362. continue;
  363. pg_idx = page_index(req->wb_page);
  364. if (pg_idx < idx_start)
  365. continue;
  366. if (pg_idx > idx_end)
  367. break;
  368. if (!nfs_lock_request(req))
  369. continue;
  370. nfs_list_remove_request(req);
  371. nfs_list_add_request(req, dst);
  372. __nfs_del_lru(req);
  373. __nfs_add_lru(&NFS_SERVER(req->wb_inode)->lru_busy, req);
  374. res++;
  375. }
  376. return res;
  377. }
  378. /*
  379.  * nfs_try_to_free_pages - Free up NFS read/write requests
  380.  * @server: The NFS superblock
  381.  *
  382.  * This function attempts to flush out NFS reads and writes in order
  383.  * to keep the hard limit on the total number of pending requests
  384.  * on a given NFS partition.
  385.  * Note: we first try to commit unstable writes, then flush out pending
  386.  *       reads, then finally the dirty pages.
  387.  *       The assumption is that this reflects the ordering from the fastest
  388.  *       to the slowest method for reclaiming requests.
  389.  */
  390. static int
  391. nfs_try_to_free_pages(struct nfs_server *server)
  392. {
  393. LIST_HEAD(head);
  394. struct nfs_page *req = NULL;
  395. int nreq;
  396. for (;;) {
  397. if (req) {
  398. int status = nfs_wait_on_request(req);
  399. nfs_release_request(req);
  400. if (status)
  401. break;
  402. req = NULL;
  403. }
  404. nreq = atomic_read(&server->rw_requests->nr_requests);
  405. if (nreq < MAX_REQUEST_HARD)
  406. return 1;
  407. spin_lock(&nfs_wreq_lock);
  408. /* Are there any busy RPC calls that might free up requests? */
  409. if (!list_empty(&server->lru_busy)) {
  410. req = nfs_lru_entry(server->lru_busy.next);
  411. req->wb_count++;
  412. __nfs_del_lru(req);
  413. spin_unlock(&nfs_wreq_lock);
  414. continue;
  415. }
  416. #ifdef CONFIG_NFS_V3
  417. /* Let's try to free up some completed NFSv3 unstable writes */
  418. nfs_scan_lru_commit(server, &head);
  419. if (!list_empty(&head)) {
  420. spin_unlock(&nfs_wreq_lock);
  421. nfs_commit_list(&head, 0);
  422. continue;
  423. }
  424. #endif
  425. /* OK, so we try to free up some pending readaheads */
  426. nfs_scan_lru_read(server, &head);
  427. if (!list_empty(&head)) {
  428. spin_unlock(&nfs_wreq_lock);
  429. nfs_pagein_list(&head, server->rpages);
  430. continue;
  431. }
  432. /* Last resort: we try to flush out single requests */
  433. nfs_scan_lru_dirty(server, &head);
  434. if (!list_empty(&head)) {
  435. spin_unlock(&nfs_wreq_lock);
  436. nfs_flush_list(&head, server->wpages, FLUSH_STABLE);
  437. continue;
  438. }
  439. spin_unlock(&nfs_wreq_lock);
  440. break;
  441. }
  442. /* We failed to free up requests */
  443. return 0;
  444. }
  445. int nfs_init_nfspagecache(void)
  446. {
  447. nfs_page_cachep = kmem_cache_create("nfs_page",
  448.     sizeof(struct nfs_page),
  449.     0, SLAB_HWCACHE_ALIGN,
  450.     NULL, NULL);
  451. if (nfs_page_cachep == NULL)
  452. return -ENOMEM;
  453. return 0;
  454. }
  455. void nfs_destroy_nfspagecache(void)
  456. {
  457. if (kmem_cache_destroy(nfs_page_cachep))
  458. printk(KERN_INFO "nfs_page: not all structures were freedn");
  459. }