linux/fs/freevxfs/vxfs_lookup.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2001 Christoph Hellwig.
   3 * Copyright (c) 2016 Krzysztof Blaszkowski
   4 * All rights reserved.
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions, and the following disclaimer,
  11 *    without modification.
  12 * 2. The name of the author may not be used to endorse or promote products
  13 *    derived from this software without specific prior written permission.
  14 *
  15 * Alternatively, this software may be distributed under the terms of the
  16 * GNU General Public License ("GPL").
  17 *
  18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28 * SUCH DAMAGE.
  29 */
  30
  31/*
  32 * Veritas filesystem driver - lookup and other directory related code.
  33 */
  34#include <linux/fs.h>
  35#include <linux/time.h>
  36#include <linux/mm.h>
  37#include <linux/highmem.h>
  38#include <linux/kernel.h>
  39#include <linux/pagemap.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_SIZE / (sbp)->s_blocksize))
  50
  51
  52static struct dentry *  vxfs_lookup(struct inode *, struct dentry *, unsigned int);
  53static int              vxfs_readdir(struct file *, struct dir_context *);
  54
  55const struct inode_operations vxfs_dir_inode_ops = {
  56        .lookup =               vxfs_lookup,
  57};
  58
  59const struct file_operations vxfs_dir_operations = {
  60        .llseek =               generic_file_llseek,
  61        .read =                 generic_read_dir,
  62        .iterate_shared =       vxfs_readdir,
  63};
  64
  65
  66/**
  67 * vxfs_find_entry - find a mathing directory entry for a dentry
  68 * @ip:         directory inode
  69 * @dp:         dentry for which we want to find a direct
  70 * @ppp:        gets filled with the page the return value sits in
  71 *
  72 * Description:
  73 *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
  74 *   cache entry @dp.  @ppp will be filled with the page the return
  75 *   value resides in.
  76 *
  77 * Returns:
  78 *   The wanted direct on success, else a NULL pointer.
  79 */
  80static struct vxfs_direct *
  81vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
  82{
  83        u_long bsize = ip->i_sb->s_blocksize;
  84        const char *name = dp->d_name.name;
  85        int namelen = dp->d_name.len;
  86        loff_t limit = VXFS_DIRROUND(ip->i_size);
  87        struct vxfs_direct *de_exit = NULL;
  88        loff_t pos = 0;
  89        struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
  90
  91        while (pos < limit) {
  92                struct page *pp;
  93                char *kaddr;
  94                int pg_ofs = pos & ~PAGE_MASK;
  95
  96                pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
  97                if (IS_ERR(pp))
  98                        return NULL;
  99                kaddr = (char *)page_address(pp);
 100
 101                while (pg_ofs < PAGE_SIZE && pos < limit) {
 102                        struct vxfs_direct *de;
 103
 104                        if ((pos & (bsize - 1)) < 4) {
 105                                struct vxfs_dirblk *dbp =
 106                                        (struct vxfs_dirblk *)
 107                                         (kaddr + (pos & ~PAGE_MASK));
 108                                int overhead = VXFS_DIRBLKOV(sbi, dbp);
 109
 110                                pos += overhead;
 111                                pg_ofs += overhead;
 112                        }
 113                        de = (struct vxfs_direct *)(kaddr + pg_ofs);
 114
 115                        if (!de->d_reclen) {
 116                                pos += bsize - 1;
 117                                pos &= ~(bsize - 1);
 118                                break;
 119                        }
 120
 121                        pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
 122                        pos += fs16_to_cpu(sbi, de->d_reclen);
 123                        if (!de->d_ino)
 124                                continue;
 125
 126                        if (namelen != fs16_to_cpu(sbi, de->d_namelen))
 127                                continue;
 128                        if (!memcmp(name, de->d_name, namelen)) {
 129                                *ppp = pp;
 130                                de_exit = de;
 131                                break;
 132                        }
 133                }
 134                if (!de_exit)
 135                        vxfs_put_page(pp);
 136                else
 137                        break;
 138        }
 139
 140        return de_exit;
 141}
 142
 143/**
 144 * vxfs_inode_by_name - find inode number for dentry
 145 * @dip:        directory to search in
 146 * @dp:         dentry we search for
 147 *
 148 * Description:
 149 *   vxfs_inode_by_name finds out the inode number of
 150 *   the path component described by @dp in @dip.
 151 *
 152 * Returns:
 153 *   The wanted inode number on success, else Zero.
 154 */
 155static ino_t
 156vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
 157{
 158        struct vxfs_direct              *de;
 159        struct page                     *pp;
 160        ino_t                           ino = 0;
 161
 162        de = vxfs_find_entry(dip, dp, &pp);
 163        if (de) {
 164                ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
 165                kunmap(pp);
 166                put_page(pp);
 167        }
 168        
 169        return (ino);
 170}
 171
 172/**
 173 * vxfs_lookup - lookup pathname component
 174 * @dip:        dir in which we lookup
 175 * @dp:         dentry we lookup
 176 * @flags:      lookup flags
 177 *
 178 * Description:
 179 *   vxfs_lookup tries to lookup the pathname component described
 180 *   by @dp in @dip.
 181 *
 182 * Returns:
 183 *   A NULL-pointer on success, else a negative error code encoded
 184 *   in the return pointer.
 185 */
 186static struct dentry *
 187vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
 188{
 189        struct inode            *ip = NULL;
 190        ino_t                   ino;
 191                         
 192        if (dp->d_name.len > VXFS_NAMELEN)
 193                return ERR_PTR(-ENAMETOOLONG);
 194                                 
 195        ino = vxfs_inode_by_name(dip, dp);
 196        if (ino) {
 197                ip = vxfs_iget(dip->i_sb, ino);
 198                if (IS_ERR(ip))
 199                        return ERR_CAST(ip);
 200        }
 201        d_add(dp, ip);
 202        return NULL;
 203}
 204
 205/**
 206 * vxfs_readdir - read a directory
 207 * @fp:         the directory to read
 208 * @retp:       return buffer
 209 * @filler:     filldir callback
 210 *
 211 * Description:
 212 *   vxfs_readdir fills @retp with directory entries from @fp
 213 *   using the VFS supplied callback @filler.
 214 *
 215 * Returns:
 216 *   Zero.
 217 */
 218static int
 219vxfs_readdir(struct file *fp, struct dir_context *ctx)
 220{
 221        struct inode            *ip = file_inode(fp);
 222        struct super_block      *sbp = ip->i_sb;
 223        u_long                  bsize = sbp->s_blocksize;
 224        loff_t                  pos, limit;
 225        struct vxfs_sb_info     *sbi = VXFS_SBI(sbp);
 226
 227        if (ctx->pos == 0) {
 228                if (!dir_emit_dot(fp, ctx))
 229                        goto out;
 230                ctx->pos++;
 231        }
 232        if (ctx->pos == 1) {
 233                if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
 234                        goto out;
 235                ctx->pos++;
 236        }
 237
 238        limit = VXFS_DIRROUND(ip->i_size);
 239        if (ctx->pos > limit)
 240                goto out;
 241
 242        pos = ctx->pos & ~3L;
 243
 244        while (pos < limit) {
 245                struct page *pp;
 246                char *kaddr;
 247                int pg_ofs = pos & ~PAGE_MASK;
 248                int rc = 0;
 249
 250                pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
 251                if (IS_ERR(pp))
 252                        return -ENOMEM;
 253
 254                kaddr = (char *)page_address(pp);
 255
 256                while (pg_ofs < PAGE_SIZE && pos < limit) {
 257                        struct vxfs_direct *de;
 258
 259                        if ((pos & (bsize - 1)) < 4) {
 260                                struct vxfs_dirblk *dbp =
 261                                        (struct vxfs_dirblk *)
 262                                         (kaddr + (pos & ~PAGE_MASK));
 263                                int overhead = VXFS_DIRBLKOV(sbi, dbp);
 264
 265                                pos += overhead;
 266                                pg_ofs += overhead;
 267                        }
 268                        de = (struct vxfs_direct *)(kaddr + pg_ofs);
 269
 270                        if (!de->d_reclen) {
 271                                pos += bsize - 1;
 272                                pos &= ~(bsize - 1);
 273                                break;
 274                        }
 275
 276                        pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
 277                        pos += fs16_to_cpu(sbi, de->d_reclen);
 278                        if (!de->d_ino)
 279                                continue;
 280
 281                        rc = dir_emit(ctx, de->d_name,
 282                                        fs16_to_cpu(sbi, de->d_namelen),
 283                                        fs32_to_cpu(sbi, de->d_ino),
 284                                        DT_UNKNOWN);
 285                        if (!rc) {
 286                                /* the dir entry was not read, fix pos. */
 287                                pos -= fs16_to_cpu(sbi, de->d_reclen);
 288                                break;
 289                        }
 290                }
 291                vxfs_put_page(pp);
 292                if (!rc)
 293                        break;
 294        }
 295
 296        ctx->pos = pos | 2;
 297
 298out:
 299        return 0;
 300}
 301