vxfs_lookup.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright (c) 2000-2001 Christoph Hellwig.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions, and the following disclaimer,
  10. * without modification.
  11. * 2. The name of the author may not be used to endorse or promote products
  12. * derived from this software without specific prior written permission.
  13. *
  14. * Alternatively, this software may be distributed under the terms of the
  15. * GNU General Public License ("GPL").
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  21. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * Veritas filesystem driver - lookup and other directory related code.
  31. */
  32. #include <linux/fs.h>
  33. #include <linux/time.h>
  34. #include <linux/mm.h>
  35. #include <linux/highmem.h>
  36. #include <linux/kernel.h>
  37. #include <linux/pagemap.h>
  38. #include <linux/smp_lock.h>
  39. #include "vxfs.h"
  40. #include "vxfs_dir.h"
  41. #include "vxfs_inode.h"
  42. #include "vxfs_extern.h"
  43. /*
  44. * Number of VxFS blocks per page.
  45. */
  46. #define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
  47. static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
  48. static int vxfs_readdir(struct file *, void *, filldir_t);
  49. const struct inode_operations vxfs_dir_inode_ops = {
  50. .lookup = vxfs_lookup,
  51. };
  52. const struct file_operations vxfs_dir_operations = {
  53. .llseek = generic_file_llseek,
  54. .read = generic_read_dir,
  55. .readdir = vxfs_readdir,
  56. };
  57. static inline u_long
  58. dir_pages(struct inode *inode)
  59. {
  60. return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  61. }
  62. static inline u_long
  63. dir_blocks(struct inode *ip)
  64. {
  65. u_long bsize = ip->i_sb->s_blocksize;
  66. return (ip->i_size + bsize - 1) & ~(bsize - 1);
  67. }
  68. /*
  69. * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
  70. *
  71. * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
  72. */
  73. static inline int
  74. vxfs_match(int len, const char * const name, struct vxfs_direct *de)
  75. {
  76. if (len != de->d_namelen)
  77. return 0;
  78. if (!de->d_ino)
  79. return 0;
  80. return !memcmp(name, de->d_name, len);
  81. }
  82. static inline struct vxfs_direct *
  83. vxfs_next_entry(struct vxfs_direct *de)
  84. {
  85. return ((struct vxfs_direct *)((char*)de + de->d_reclen));
  86. }
  87. /**
  88. * vxfs_find_entry - find a mathing directory entry for a dentry
  89. * @ip: directory inode
  90. * @dp: dentry for which we want to find a direct
  91. * @ppp: gets filled with the page the return value sits in
  92. *
  93. * Description:
  94. * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
  95. * cache entry @dp. @ppp will be filled with the page the return
  96. * value resides in.
  97. *
  98. * Returns:
  99. * The wanted direct on success, else a NULL pointer.
  100. */
  101. static struct vxfs_direct *
  102. vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
  103. {
  104. u_long npages, page, nblocks, pblocks, block;
  105. u_long bsize = ip->i_sb->s_blocksize;
  106. const char *name = dp->d_name.name;
  107. int namelen = dp->d_name.len;
  108. npages = dir_pages(ip);
  109. nblocks = dir_blocks(ip);
  110. pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
  111. for (page = 0; page < npages; page++) {
  112. caddr_t kaddr;
  113. struct page *pp;
  114. pp = vxfs_get_page(ip->i_mapping, page);
  115. if (IS_ERR(pp))
  116. continue;
  117. kaddr = (caddr_t)page_address(pp);
  118. for (block = 0; block <= nblocks && block <= pblocks; block++) {
  119. caddr_t baddr, limit;
  120. struct vxfs_dirblk *dbp;
  121. struct vxfs_direct *de;
  122. baddr = kaddr + (block * bsize);
  123. limit = baddr + bsize - VXFS_DIRLEN(1);
  124. dbp = (struct vxfs_dirblk *)baddr;
  125. de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
  126. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  127. if (!de->d_reclen)
  128. break;
  129. if (!de->d_ino)
  130. continue;
  131. if (vxfs_match(namelen, name, de)) {
  132. *ppp = pp;
  133. return (de);
  134. }
  135. }
  136. }
  137. vxfs_put_page(pp);
  138. }
  139. return NULL;
  140. }
  141. /**
  142. * vxfs_inode_by_name - find inode number for dentry
  143. * @dip: directory to search in
  144. * @dp: dentry we seach for
  145. *
  146. * Description:
  147. * vxfs_inode_by_name finds out the inode number of
  148. * the path component described by @dp in @dip.
  149. *
  150. * Returns:
  151. * The wanted inode number on success, else Zero.
  152. */
  153. static ino_t
  154. vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  155. {
  156. struct vxfs_direct *de;
  157. struct page *pp;
  158. ino_t ino = 0;
  159. de = vxfs_find_entry(dip, dp, &pp);
  160. if (de) {
  161. ino = de->d_ino;
  162. kunmap(pp);
  163. page_cache_release(pp);
  164. }
  165. return (ino);
  166. }
  167. /**
  168. * vxfs_lookup - lookup pathname component
  169. * @dip: dir in which we lookup
  170. * @dp: dentry we lookup
  171. * @nd: lookup nameidata
  172. *
  173. * Description:
  174. * vxfs_lookup tries to lookup the pathname component described
  175. * by @dp in @dip.
  176. *
  177. * Returns:
  178. * A NULL-pointer on success, else an negative error code encoded
  179. * in the return pointer.
  180. */
  181. static struct dentry *
  182. vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
  183. {
  184. struct inode *ip = NULL;
  185. ino_t ino;
  186. if (dp->d_name.len > VXFS_NAMELEN)
  187. return ERR_PTR(-ENAMETOOLONG);
  188. lock_kernel();
  189. ino = vxfs_inode_by_name(dip, dp);
  190. if (ino) {
  191. ip = vxfs_iget(dip->i_sb, ino);
  192. if (IS_ERR(ip)) {
  193. unlock_kernel();
  194. return ERR_CAST(ip);
  195. }
  196. }
  197. unlock_kernel();
  198. d_add(dp, ip);
  199. return NULL;
  200. }
  201. /**
  202. * vxfs_readdir - read a directory
  203. * @fp: the directory to read
  204. * @retp: return buffer
  205. * @filler: filldir callback
  206. *
  207. * Description:
  208. * vxfs_readdir fills @retp with directory entries from @fp
  209. * using the VFS supplied callback @filler.
  210. *
  211. * Returns:
  212. * Zero.
  213. */
  214. static int
  215. vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
  216. {
  217. struct inode *ip = fp->f_path.dentry->d_inode;
  218. struct super_block *sbp = ip->i_sb;
  219. u_long bsize = sbp->s_blocksize;
  220. u_long page, npages, block, pblocks, nblocks, offset;
  221. loff_t pos;
  222. lock_kernel();
  223. switch ((long)fp->f_pos) {
  224. case 0:
  225. if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
  226. goto out;
  227. fp->f_pos++;
  228. /* fallthrough */
  229. case 1:
  230. if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
  231. goto out;
  232. fp->f_pos++;
  233. /* fallthrough */
  234. }
  235. pos = fp->f_pos - 2;
  236. if (pos > VXFS_DIRROUND(ip->i_size)) {
  237. unlock_kernel();
  238. return 0;
  239. }
  240. npages = dir_pages(ip);
  241. nblocks = dir_blocks(ip);
  242. pblocks = VXFS_BLOCK_PER_PAGE(sbp);
  243. page = pos >> PAGE_CACHE_SHIFT;
  244. offset = pos & ~PAGE_CACHE_MASK;
  245. block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
  246. for (; page < npages; page++, block = 0) {
  247. caddr_t kaddr;
  248. struct page *pp;
  249. pp = vxfs_get_page(ip->i_mapping, page);
  250. if (IS_ERR(pp))
  251. continue;
  252. kaddr = (caddr_t)page_address(pp);
  253. for (; block <= nblocks && block <= pblocks; block++) {
  254. caddr_t baddr, limit;
  255. struct vxfs_dirblk *dbp;
  256. struct vxfs_direct *de;
  257. baddr = kaddr + (block * bsize);
  258. limit = baddr + bsize - VXFS_DIRLEN(1);
  259. dbp = (struct vxfs_dirblk *)baddr;
  260. de = (struct vxfs_direct *)
  261. (offset ?
  262. (kaddr + offset) :
  263. (baddr + VXFS_DIRBLKOV(dbp)));
  264. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  265. int over;
  266. if (!de->d_reclen)
  267. break;
  268. if (!de->d_ino)
  269. continue;
  270. offset = (caddr_t)de - kaddr;
  271. over = filler(retp, de->d_name, de->d_namelen,
  272. ((page << PAGE_CACHE_SHIFT) | offset) + 2,
  273. de->d_ino, DT_UNKNOWN);
  274. if (over) {
  275. vxfs_put_page(pp);
  276. goto done;
  277. }
  278. }
  279. offset = 0;
  280. }
  281. vxfs_put_page(pp);
  282. offset = 0;
  283. }
  284. done:
  285. fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
  286. out:
  287. unlock_kernel();
  288. return 0;
  289. }