cache.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  cache.c
  3.  *
  4.  * Copyright (C) 1997 by Bill Hawes
  5.  *
  6.  * Routines to support directory cacheing using the page cache.
  7.  * This cache code is almost directly taken from ncpfs.
  8.  *
  9.  * Please add a note about your changes to smbfs in the ChangeLog file.
  10.  */
  11. #include <linux/sched.h>
  12. #include <linux/errno.h>
  13. #include <linux/kernel.h>
  14. #include <linux/mm.h>
  15. #include <linux/dirent.h>
  16. #include <linux/smb_fs.h>
  17. #include <linux/pagemap.h>
  18. #include <asm/page.h>
  19. #include "smb_debug.h"
  20. #include "proto.h"
  21. /*
  22.  * Force the next attempt to use the cache to be a timeout.
  23.  * If we can't find the page that's fine, it will cause a refresh.
  24.  */
  25. void
  26. smb_invalid_dir_cache(struct inode * dir)
  27. {
  28. struct smb_sb_info *server = server_from_inode(dir);
  29. union  smb_dir_cache *cache = NULL;
  30. struct page *page = NULL;
  31. page = grab_cache_page(&dir->i_data, 0);
  32. if (!page)
  33. goto out;
  34. if (!Page_Uptodate(page))
  35. goto out_unlock;
  36. cache = kmap(page);
  37. cache->head.time = jiffies - SMB_MAX_AGE(server);
  38. kunmap(page);
  39. SetPageUptodate(page);
  40. out_unlock:
  41. UnlockPage(page);
  42. page_cache_release(page);
  43. out:
  44. return;
  45. }
  46. /*
  47.  * Mark all dentries for 'parent' as invalid, forcing them to be re-read
  48.  */
  49. void
  50. smb_invalidate_dircache_entries(struct dentry *parent)
  51. {
  52. struct smb_sb_info *server = server_from_dentry(parent);
  53. struct list_head *next;
  54. struct dentry *dentry;
  55. spin_lock(&dcache_lock);
  56. next = parent->d_subdirs.next;
  57. while (next != &parent->d_subdirs) {
  58. dentry = list_entry(next, struct dentry, d_child);
  59. dentry->d_fsdata = NULL;
  60. smb_age_dentry(server, dentry);
  61. next = next->next;
  62. }
  63. spin_unlock(&dcache_lock);
  64. }
  65. /*
  66.  * dget, but require that fpos and parent matches what the dentry contains.
  67.  * dentry is not known to be a valid pointer at entry.
  68.  */
  69. struct dentry *
  70. smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
  71. {
  72. struct dentry *dent = dentry;
  73. struct list_head *next;
  74. if (d_validate(dent, parent)) {
  75. if (dent->d_name.len <= SMB_MAXPATHLEN &&
  76.     (unsigned long)dent->d_fsdata == fpos) {
  77. if (!dent->d_inode) {
  78. dput(dent);
  79. dent = NULL;
  80. }
  81. return dent;
  82. }
  83. dput(dent);
  84. }
  85. /* If a pointer is invalid, we search the dentry. */
  86. spin_lock(&dcache_lock);
  87. next = parent->d_subdirs.next;
  88. while (next != &parent->d_subdirs) {
  89. dent = list_entry(next, struct dentry, d_child);
  90. if ((unsigned long)dent->d_fsdata == fpos) {
  91. if (dent->d_inode)
  92. dget_locked(dent);
  93. else
  94. dent = NULL;
  95. goto out_unlock;
  96. }
  97. next = next->next;
  98. }
  99. dent = NULL;
  100. out_unlock:
  101. spin_unlock(&dcache_lock);
  102. return dent;
  103. }
  104. /*
  105.  * Create dentry/inode for this file and add it to the dircache.
  106.  */
  107. int
  108. smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
  109.        struct smb_cache_control *ctrl, struct qstr *qname,
  110.        struct smb_fattr *entry)
  111. {
  112. struct dentry *newdent, *dentry = filp->f_dentry;
  113. struct inode *newino, *inode = dentry->d_inode;
  114. struct smb_cache_control ctl = *ctrl;
  115. int valid = 0;
  116. int hashed = 0;
  117. ino_t ino = 0;
  118. qname->hash = full_name_hash(qname->name, qname->len);
  119. if (dentry->d_op && dentry->d_op->d_hash)
  120. if (dentry->d_op->d_hash(dentry, qname) != 0)
  121. goto end_advance;
  122. newdent = d_lookup(dentry, qname);
  123. if (!newdent) {
  124. newdent = d_alloc(dentry, qname);
  125. if (!newdent)
  126. goto end_advance;
  127. } else {
  128. hashed = 1;
  129. memcpy((char *) newdent->d_name.name, qname->name,
  130.        newdent->d_name.len);
  131. }
  132. if (!newdent->d_inode) {
  133. smb_renew_times(newdent);
  134. entry->f_ino = iunique(inode->i_sb, 2);
  135. newino = smb_iget(inode->i_sb, entry);
  136. if (newino) {
  137. smb_new_dentry(newdent);
  138. d_instantiate(newdent, newino);
  139. if (!hashed)
  140. d_rehash(newdent);
  141. }
  142. } else
  143. smb_set_inode_attr(newdent->d_inode, entry);
  144.         if (newdent->d_inode) {
  145. ino = newdent->d_inode->i_ino;
  146. newdent->d_fsdata = (void *) ctl.fpos;
  147. smb_new_dentry(newdent);
  148. }
  149. if (ctl.idx >= SMB_DIRCACHE_SIZE) {
  150. if (ctl.page) {
  151. kunmap(ctl.page);
  152. SetPageUptodate(ctl.page);
  153. UnlockPage(ctl.page);
  154. page_cache_release(ctl.page);
  155. }
  156. ctl.cache = NULL;
  157. ctl.idx  -= SMB_DIRCACHE_SIZE;
  158. ctl.ofs  += 1;
  159. ctl.page  = grab_cache_page(&inode->i_data, ctl.ofs);
  160. if (ctl.page)
  161. ctl.cache = kmap(ctl.page);
  162. }
  163. if (ctl.cache) {
  164. ctl.cache->dentry[ctl.idx] = newdent;
  165. valid = 1;
  166. }
  167. dput(newdent);
  168. end_advance:
  169. if (!valid)
  170. ctl.valid = 0;
  171. if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
  172. if (!ino)
  173. ino = find_inode_number(dentry, qname);
  174. if (!ino)
  175. ino = iunique(inode->i_sb, 2);
  176. ctl.filled = filldir(dirent, qname->name, qname->len,
  177.      filp->f_pos, ino, DT_UNKNOWN);
  178. if (!ctl.filled)
  179. filp->f_pos += 1;
  180. }
  181. ctl.fpos += 1;
  182. ctl.idx  += 1;
  183. *ctrl = ctl;
  184. return (ctl.valid || !ctl.filled);
  185. }