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