linux-bk/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
  55struct inode_operations vxfs_dir_inode_ops = {
  56        .lookup =               vxfs_lookup,
  57};
  58
  59struct 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 = iget(dip->i_sb, ino);
 217                if (!ip) {
 218                        unlock_kernel();
 219                        return ERR_PTR(-EACCES);
 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_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        switch ((long)fp->f_pos) {
 250        case 0:
 251                if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
 252                        goto out;
 253                fp->f_pos++;
 254                /* fallthrough */
 255        case 1:
 256                if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
 257                        goto out;
 258                fp->f_pos++;
 259                /* fallthrough */
 260        }
 261
 262        pos = fp->f_pos - 2;
 263        
 264        if (pos > VXFS_DIRROUND(ip->i_size)) {
 265                unlock_kernel();
 266                return 0;
 267        }
 268
 269        npages = dir_pages(ip);
 270        nblocks = dir_blocks(ip);
 271        pblocks = VXFS_BLOCK_PER_PAGE(sbp);
 272
 273        page = pos >> PAGE_CACHE_SHIFT;
 274        offset = pos & ~PAGE_CACHE_MASK;
 275        block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
 276
 277        for (; page < npages; page++, block = 0) {
 278                caddr_t                 kaddr;
 279                struct page             *pp;
 280
 281                pp = vxfs_get_page(ip->i_mapping, page);
 282                if (IS_ERR(pp))
 283                        continue;
 284                kaddr = (caddr_t)page_address(pp);
 285
 286                for (; block <= nblocks && block <= pblocks; block++) {
 287                        caddr_t                 baddr, limit;
 288                        struct vxfs_dirblk      *dbp;
 289                        struct vxfs_direct      *de;
 290
 291                        baddr = kaddr + (block * bsize);
 292                        limit = baddr + bsize - VXFS_DIRLEN(1);
 293        
 294                        dbp = (struct vxfs_dirblk *)baddr;
 295                        de = (struct vxfs_direct *)
 296                                (offset ?
 297                                 (kaddr + offset) :
 298                                 (baddr + VXFS_DIRBLKOV(dbp)));
 299
 300                        for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
 301                                int     over;
 302
 303                                if (!de->d_reclen)
 304                                        break;
 305                                if (!de->d_ino)
 306                                        continue;
 307
 308                                offset = (caddr_t)de - kaddr;
 309                                over = filler(retp, de->d_name, de->d_namelen,
 310                                        ((page << PAGE_CACHE_SHIFT) | offset) + 2,
 311                                        de->d_ino, DT_UNKNOWN);
 312                                if (over) {
 313                                        vxfs_put_page(pp);
 314                                        goto done;
 315                                }
 316                        }
 317                        offset = 0;
 318                }
 319                vxfs_put_page(pp);
 320                offset = 0;
 321        }
 322
 323done:
 324        fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
 325out:
 326        unlock_kernel();
 327        return 0;
 328}
 329
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.