vxfs_lookup.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 *, unsigned int);
  47. static int vxfs_readdir(struct file *, struct dir_context *);
  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. .iterate = 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, unsigned int flags)
  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, struct dir_context *ctx)
  211. {
  212. struct inode *ip = file_inode(fp);
  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. if (ctx->pos == 0) {
  218. if (!dir_emit_dot(fp, ctx))
  219. return 0;
  220. ctx->pos = 1;
  221. }
  222. if (ctx->pos == 1) {
  223. if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
  224. return 0;
  225. ctx->pos = 2;
  226. }
  227. pos = ctx->pos - 2;
  228. if (pos > VXFS_DIRROUND(ip->i_size))
  229. return 0;
  230. npages = dir_pages(ip);
  231. nblocks = dir_blocks(ip);
  232. pblocks = VXFS_BLOCK_PER_PAGE(sbp);
  233. page = pos >> PAGE_CACHE_SHIFT;
  234. offset = pos & ~PAGE_CACHE_MASK;
  235. block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
  236. for (; page < npages; page++, block = 0) {
  237. char *kaddr;
  238. struct page *pp;
  239. pp = vxfs_get_page(ip->i_mapping, page);
  240. if (IS_ERR(pp))
  241. continue;
  242. kaddr = (char *)page_address(pp);
  243. for (; block <= nblocks && block <= pblocks; block++) {
  244. char *baddr, *limit;
  245. struct vxfs_dirblk *dbp;
  246. struct vxfs_direct *de;
  247. baddr = kaddr + (block * bsize);
  248. limit = baddr + bsize - VXFS_DIRLEN(1);
  249. dbp = (struct vxfs_dirblk *)baddr;
  250. de = (struct vxfs_direct *)
  251. (offset ?
  252. (kaddr + offset) :
  253. (baddr + VXFS_DIRBLKOV(dbp)));
  254. for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
  255. if (!de->d_reclen)
  256. break;
  257. if (!de->d_ino)
  258. continue;
  259. offset = (char *)de - kaddr;
  260. ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
  261. if (!dir_emit(ctx, de->d_name, de->d_namelen,
  262. de->d_ino, DT_UNKNOWN)) {
  263. vxfs_put_page(pp);
  264. return 0;
  265. }
  266. }
  267. offset = 0;
  268. }
  269. vxfs_put_page(pp);
  270. offset = 0;
  271. }
  272. ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
  273. return 0;
  274. }