vxfs_lookup.c 8.0 KB

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