vxfs_lookup.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 "vxfs.h"
  39. #include "vxfs_dir.h"
  40. #include "vxfs_inode.h"
  41. #include "vxfs_extern.h"
  42. /*
  43. * Number of VxFS blocks per page.
  44. */
  45. #define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
  46. static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
  47. static int vxfs_readdir(struct file *, void *, filldir_t);
  48. const struct inode_operations vxfs_dir_inode_ops = {
  49. .lookup = vxfs_lookup,
  50. };
  51. const struct file_operations vxfs_dir_operations = {
  52. .llseek = generic_file_llseek,
  53. .read = generic_read_dir,
  54. .readdir = vxfs_readdir,
  55. };
  56. static inline u_long
  57. dir_pages(struct inode *inode)
  58. {
  59. return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  60. }
  61. static inline u_long
  62. dir_blocks(struct inode *ip)
  63. {
  64. u_long bsize = ip->i_sb->s_blocksize;
  65. return (ip->i_size + bsize - 1) & ~(bsize - 1);
  66. }
  67. /*
  68. * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
  69. *
  70. * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
  71. */
  72. static inline int
  73. vxfs_match(int len, const char * const name, struct vxfs_direct *de)
  74. {
  75. if (len != de->d_namelen)
  76. return 0;
  77. if (!de->d_ino)
  78. return 0;
  79. return !memcmp(name, de->d_name, len);
  80. }
  81. static inline struct vxfs_direct *
  82. vxfs_next_entry(struct vxfs_direct *de)
  83. {
  84. return ((struct vxfs_direct *)((char*)de + de->d_reclen));
  85. }
  86. /**
  87. * vxfs_find_entry - find a mathing directory entry for a dentry
  88. * @ip: directory inode
  89. * @dp: dentry for which we want to find a direct
  90. * @ppp: gets filled with the page the return value sits in
  91. *
  92. * Description:
  93. * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
  94. * cache entry @dp. @ppp will be filled with the page the return
  95. * value resides in.
  96. *
  97. * Returns:
  98. * The wanted direct on success, else a NULL pointer.
  99. */
  100. static struct vxfs_direct *
  101. vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
  102. {
  103. u_long npages, page, nblocks, pblocks, block;
  104. u_long bsize = ip->i_sb->s_blocksize;
  105. const char *name = dp->d_name.name;
  106. int namelen = dp->d_name.len;
  107. npages = dir_pages(ip);
  108. nblocks = dir_blocks(ip);
  109. pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
  110. for (page = 0; page < npages; page++) {
  111. caddr_t kaddr;
  112. struct page *pp;
  113. pp = vxfs_get_page(ip->i_mapping, page);
  114. if (IS_ERR(pp))
  115. continue;
  116. kaddr = (caddr_t)page_address(pp);
  117. for (block = 0; block <= nblocks && block <= pblocks; block++) {
  118. caddr_t baddr, limit;
  119. struct vxfs_dirblk *dbp;
  120. struct vxfs_direct *de;
  121. baddr = kaddr + (block * bsize);
  122. limit = baddr + bsize - VXFS_DIRLEN(1);
  123. dbp = (struct vxfs_dirblk *)baddr;
  124. de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
  125. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  126. if (!de->d_reclen)
  127. break;
  128. if (!de->d_ino)
  129. continue;
  130. if (vxfs_match(namelen, name, de)) {
  131. *ppp = pp;
  132. return (de);
  133. }
  134. }
  135. }
  136. vxfs_put_page(pp);
  137. }
  138. return NULL;
  139. }
  140. /**
  141. * vxfs_inode_by_name - find inode number for dentry
  142. * @dip: directory to search in
  143. * @dp: dentry we search for
  144. *
  145. * Description:
  146. * vxfs_inode_by_name finds out the inode number of
  147. * the path component described by @dp in @dip.
  148. *
  149. * Returns:
  150. * The wanted inode number on success, else Zero.
  151. */
  152. static ino_t
  153. vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  154. {
  155. struct vxfs_direct *de;
  156. struct page *pp;
  157. ino_t ino = 0;
  158. de = vxfs_find_entry(dip, dp, &pp);
  159. if (de) {
  160. ino = de->d_ino;
  161. kunmap(pp);
  162. page_cache_release(pp);
  163. }
  164. return (ino);
  165. }
  166. /**
  167. * vxfs_lookup - lookup pathname component
  168. * @dip: dir in which we lookup
  169. * @dp: dentry we lookup
  170. * @nd: lookup nameidata
  171. *
  172. * Description:
  173. * vxfs_lookup tries to lookup the pathname component described
  174. * by @dp in @dip.
  175. *
  176. * Returns:
  177. * A NULL-pointer on success, else an negative error code encoded
  178. * in the return pointer.
  179. */
  180. static struct dentry *
  181. vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
  182. {
  183. struct inode *ip = NULL;
  184. ino_t ino;
  185. if (dp->d_name.len > VXFS_NAMELEN)
  186. return ERR_PTR(-ENAMETOOLONG);
  187. ino = vxfs_inode_by_name(dip, dp);
  188. if (ino) {
  189. ip = vxfs_iget(dip->i_sb, ino);
  190. if (IS_ERR(ip))
  191. return ERR_CAST(ip);
  192. }
  193. d_add(dp, ip);
  194. return NULL;
  195. }
  196. /**
  197. * vxfs_readdir - read a directory
  198. * @fp: the directory to read
  199. * @retp: return buffer
  200. * @filler: filldir callback
  201. *
  202. * Description:
  203. * vxfs_readdir fills @retp with directory entries from @fp
  204. * using the VFS supplied callback @filler.
  205. *
  206. * Returns:
  207. * Zero.
  208. */
  209. static int
  210. vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
  211. {
  212. struct inode *ip = fp->f_path.dentry->d_inode;
  213. struct super_block *sbp = ip->i_sb;
  214. u_long bsize = sbp->s_blocksize;
  215. u_long page, npages, block, pblocks, nblocks, offset;
  216. loff_t pos;
  217. switch ((long)fp->f_pos) {
  218. case 0:
  219. if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
  220. goto out;
  221. fp->f_pos++;
  222. /* fallthrough */
  223. case 1:
  224. if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
  225. goto out;
  226. fp->f_pos++;
  227. /* fallthrough */
  228. }
  229. pos = fp->f_pos - 2;
  230. if (pos > VXFS_DIRROUND(ip->i_size))
  231. return 0;
  232. npages = dir_pages(ip);
  233. nblocks = dir_blocks(ip);
  234. pblocks = VXFS_BLOCK_PER_PAGE(sbp);
  235. page = pos >> PAGE_CACHE_SHIFT;
  236. offset = pos & ~PAGE_CACHE_MASK;
  237. block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
  238. for (; page < npages; page++, block = 0) {
  239. caddr_t kaddr;
  240. struct page *pp;
  241. pp = vxfs_get_page(ip->i_mapping, page);
  242. if (IS_ERR(pp))
  243. continue;
  244. kaddr = (caddr_t)page_address(pp);
  245. for (; block <= nblocks && block <= pblocks; block++) {
  246. caddr_t baddr, limit;
  247. struct vxfs_dirblk *dbp;
  248. struct vxfs_direct *de;
  249. baddr = kaddr + (block * bsize);
  250. limit = baddr + bsize - VXFS_DIRLEN(1);
  251. dbp = (struct vxfs_dirblk *)baddr;
  252. de = (struct vxfs_direct *)
  253. (offset ?
  254. (kaddr + offset) :
  255. (baddr + VXFS_DIRBLKOV(dbp)));
  256. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  257. int over;
  258. if (!de->d_reclen)
  259. break;
  260. if (!de->d_ino)
  261. continue;
  262. offset = (caddr_t)de - kaddr;
  263. over = filler(retp, de->d_name, de->d_namelen,
  264. ((page << PAGE_CACHE_SHIFT) | offset) + 2,
  265. de->d_ino, DT_UNKNOWN);
  266. if (over) {
  267. vxfs_put_page(pp);
  268. goto done;
  269. }
  270. }
  271. offset = 0;
  272. }
  273. vxfs_put_page(pp);
  274. offset = 0;
  275. }
  276. done:
  277. fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
  278. out:
  279. return 0;
  280. }