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