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