linux/fs/ext2/namei.c
<<
>>
Prefs
   1/*
   2 * linux/fs/ext2/namei.c
   3 *
   4 * Rewrite to pagecache. Almost all code had been changed, so blame me
   5 * if the things go wrong. Please, send bug reports to
   6 * viro@parcelfarce.linux.theplanet.co.uk
   7 *
   8 * Stuff here is basically a glue between the VFS and generic UNIXish
   9 * filesystem that keeps everything in pagecache. All knowledge of the
  10 * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable
  11 * and it's easier to debug that way. In principle we might want to
  12 * generalize that a bit and turn it into a library. Or not.
  13 *
  14 * The only non-static object here is ext2_dir_inode_operations.
  15 *
  16 * TODO: get rid of kmap() use, add readahead.
  17 *
  18 * Copyright (C) 1992, 1993, 1994, 1995
  19 * Remy Card (card@masi.ibp.fr)
  20 * Laboratoire MASI - Institut Blaise Pascal
  21 * Universite Pierre et Marie Curie (Paris VI)
  22 *
  23 *  from
  24 *
  25 *  linux/fs/minix/namei.c
  26 *
  27 *  Copyright (C) 1991, 1992  Linus Torvalds
  28 *
  29 *  Big-endian to little-endian byte-swapping/bitmaps by
  30 *        David S. Miller (davem@caip.rutgers.edu), 1995
  31 */
  32
  33#include <linux/pagemap.h>
  34#include "ext2.h"
  35#include "xattr.h"
  36#include "acl.h"
  37#include "xip.h"
  38
  39static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
  40{
  41        int err = ext2_add_link(dentry, inode);
  42        if (!err) {
  43                d_instantiate(dentry, inode);
  44                unlock_new_inode(inode);
  45                return 0;
  46        }
  47        inode_dec_link_count(inode);
  48        unlock_new_inode(inode);
  49        iput(inode);
  50        return err;
  51}
  52
  53/*
  54 * Methods themselves.
  55 */
  56
  57static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
  58{
  59        struct inode * inode;
  60        ino_t ino;
  61        
  62        if (dentry->d_name.len > EXT2_NAME_LEN)
  63                return ERR_PTR(-ENAMETOOLONG);
  64
  65        ino = ext2_inode_by_name(dir, &dentry->d_name);
  66        inode = NULL;
  67        if (ino) {
  68                inode = ext2_iget(dir->i_sb, ino);
  69                if (unlikely(IS_ERR(inode))) {
  70                        if (PTR_ERR(inode) == -ESTALE) {
  71                                ext2_error(dir->i_sb, __func__,
  72                                                "deleted inode referenced: %lu",
  73                                                (unsigned long) ino);
  74                                return ERR_PTR(-EIO);
  75                        } else {
  76                                return ERR_CAST(inode);
  77                        }
  78                }
  79        }
  80        return d_splice_alias(inode, dentry);
  81}
  82
  83struct dentry *ext2_get_parent(struct dentry *child)
  84{
  85        struct qstr dotdot = {.name = "..", .len = 2};
  86        unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
  87        if (!ino)
  88                return ERR_PTR(-ENOENT);
  89        return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino));
  90} 
  91
  92/*
  93 * By the time this is called, we already have created
  94 * the directory cache entry for the new file, but it
  95 * is so far negative - it has no inode.
  96 *
  97 * If the create succeeds, we fill in the inode information
  98 * with d_instantiate(). 
  99 */
 100static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd)
 101{
 102        struct inode * inode = ext2_new_inode (dir, mode);
 103        int err = PTR_ERR(inode);
 104        if (!IS_ERR(inode)) {
 105                inode->i_op = &ext2_file_inode_operations;
 106                if (ext2_use_xip(inode->i_sb)) {
 107                        inode->i_mapping->a_ops = &ext2_aops_xip;
 108                        inode->i_fop = &ext2_xip_file_operations;
 109                } else if (test_opt(inode->i_sb, NOBH)) {
 110                        inode->i_mapping->a_ops = &ext2_nobh_aops;
 111                        inode->i_fop = &ext2_file_operations;
 112                } else {
 113                        inode->i_mapping->a_ops = &ext2_aops;
 114                        inode->i_fop = &ext2_file_operations;
 115                }
 116                mark_inode_dirty(inode);
 117                err = ext2_add_nondir(dentry, inode);
 118        }
 119        return err;
 120}
 121
 122static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
 123{
 124        struct inode * inode;
 125        int err;
 126
 127        if (!new_valid_dev(rdev))
 128                return -EINVAL;
 129
 130        inode = ext2_new_inode (dir, mode);
 131        err = PTR_ERR(inode);
 132        if (!IS_ERR(inode)) {
 133                init_special_inode(inode, inode->i_mode, rdev);
 134#ifdef CONFIG_EXT2_FS_XATTR
 135                inode->i_op = &ext2_special_inode_operations;
 136#endif
 137                mark_inode_dirty(inode);
 138                err = ext2_add_nondir(dentry, inode);
 139        }
 140        return err;
 141}
 142
 143static int ext2_symlink (struct inode * dir, struct dentry * dentry,
 144        const char * symname)
 145{
 146        struct super_block * sb = dir->i_sb;
 147        int err = -ENAMETOOLONG;
 148        unsigned l = strlen(symname)+1;
 149        struct inode * inode;
 150
 151        if (l > sb->s_blocksize)
 152                goto out;
 153
 154        inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
 155        err = PTR_ERR(inode);
 156        if (IS_ERR(inode))
 157                goto out;
 158
 159        if (l > sizeof (EXT2_I(inode)->i_data)) {
 160                /* slow symlink */
 161                inode->i_op = &ext2_symlink_inode_operations;
 162                if (test_opt(inode->i_sb, NOBH))
 163                        inode->i_mapping->a_ops = &ext2_nobh_aops;
 164                else
 165                        inode->i_mapping->a_ops = &ext2_aops;
 166                err = page_symlink(inode, symname, l);
 167                if (err)
 168                        goto out_fail;
 169        } else {
 170                /* fast symlink */
 171                inode->i_op = &ext2_fast_symlink_inode_operations;
 172                memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
 173                inode->i_size = l-1;
 174        }
 175        mark_inode_dirty(inode);
 176
 177        err = ext2_add_nondir(dentry, inode);
 178out:
 179        return err;
 180
 181out_fail:
 182        inode_dec_link_count(inode);
 183        unlock_new_inode(inode);
 184        iput (inode);
 185        goto out;
 186}
 187
 188static int ext2_link (struct dentry * old_dentry, struct inode * dir,
 189        struct dentry *dentry)
 190{
 191        struct inode *inode = old_dentry->d_inode;
 192        int err;
 193
 194        if (inode->i_nlink >= EXT2_LINK_MAX)
 195                return -EMLINK;
 196
 197        inode->i_ctime = CURRENT_TIME_SEC;
 198        inode_inc_link_count(inode);
 199        atomic_inc(&inode->i_count);
 200
 201        err = ext2_add_link(dentry, inode);
 202        if (!err) {
 203                d_instantiate(dentry, inode);
 204                return 0;
 205        }
 206        inode_dec_link_count(inode);
 207        iput(inode);
 208        return err;
 209}
 210
 211static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 212{
 213        struct inode * inode;
 214        int err = -EMLINK;
 215
 216        if (dir->i_nlink >= EXT2_LINK_MAX)
 217                goto out;
 218
 219        inode_inc_link_count(dir);
 220
 221        inode = ext2_new_inode (dir, S_IFDIR | mode);
 222        err = PTR_ERR(inode);
 223        if (IS_ERR(inode))
 224                goto out_dir;
 225
 226        inode->i_op = &ext2_dir_inode_operations;
 227        inode->i_fop = &ext2_dir_operations;
 228        if (test_opt(inode->i_sb, NOBH))
 229                inode->i_mapping->a_ops = &ext2_nobh_aops;
 230        else
 231                inode->i_mapping->a_ops = &ext2_aops;
 232
 233        inode_inc_link_count(inode);
 234
 235        err = ext2_make_empty(inode, dir);
 236        if (err)
 237                goto out_fail;
 238
 239        err = ext2_add_link(dentry, inode);
 240        if (err)
 241                goto out_fail;
 242
 243        d_instantiate(dentry, inode);
 244        unlock_new_inode(inode);
 245out:
 246        return err;
 247
 248out_fail:
 249        inode_dec_link_count(inode);
 250        inode_dec_link_count(inode);
 251        unlock_new_inode(inode);
 252        iput(inode);
 253out_dir:
 254        inode_dec_link_count(dir);
 255        goto out;
 256}
 257
 258static int ext2_unlink(struct inode * dir, struct dentry *dentry)
 259{
 260        struct inode * inode = dentry->d_inode;
 261        struct ext2_dir_entry_2 * de;
 262        struct page * page;
 263        int err = -ENOENT;
 264
 265        de = ext2_find_entry (dir, &dentry->d_name, &page);
 266        if (!de)
 267                goto out;
 268
 269        err = ext2_delete_entry (de, page);
 270        if (err)
 271                goto out;
 272
 273        inode->i_ctime = dir->i_ctime;
 274        inode_dec_link_count(inode);
 275        err = 0;
 276out:
 277        return err;
 278}
 279
 280static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
 281{
 282        struct inode * inode = dentry->d_inode;
 283        int err = -ENOTEMPTY;
 284
 285        if (ext2_empty_dir(inode)) {
 286                err = ext2_unlink(dir, dentry);
 287                if (!err) {
 288                        inode->i_size = 0;
 289                        inode_dec_link_count(inode);
 290                        inode_dec_link_count(dir);
 291                }
 292        }
 293        return err;
 294}
 295
 296static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
 297        struct inode * new_dir, struct dentry * new_dentry )
 298{
 299        struct inode * old_inode = old_dentry->d_inode;
 300        struct inode * new_inode = new_dentry->d_inode;
 301        struct page * dir_page = NULL;
 302        struct ext2_dir_entry_2 * dir_de = NULL;
 303        struct page * old_page;
 304        struct ext2_dir_entry_2 * old_de;
 305        int err = -ENOENT;
 306
 307        old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page);
 308        if (!old_de)
 309                goto out;
 310
 311        if (S_ISDIR(old_inode->i_mode)) {
 312                err = -EIO;
 313                dir_de = ext2_dotdot(old_inode, &dir_page);
 314                if (!dir_de)
 315                        goto out_old;
 316        }
 317
 318        if (new_inode) {
 319                struct page *new_page;
 320                struct ext2_dir_entry_2 *new_de;
 321
 322                err = -ENOTEMPTY;
 323                if (dir_de && !ext2_empty_dir (new_inode))
 324                        goto out_dir;
 325
 326                err = -ENOENT;
 327                new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
 328                if (!new_de)
 329                        goto out_dir;
 330                inode_inc_link_count(old_inode);
 331                ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
 332                new_inode->i_ctime = CURRENT_TIME_SEC;
 333                if (dir_de)
 334                        drop_nlink(new_inode);
 335                inode_dec_link_count(new_inode);
 336        } else {
 337                if (dir_de) {
 338                        err = -EMLINK;
 339                        if (new_dir->i_nlink >= EXT2_LINK_MAX)
 340                                goto out_dir;
 341                }
 342                inode_inc_link_count(old_inode);
 343                err = ext2_add_link(new_dentry, old_inode);
 344                if (err) {
 345                        inode_dec_link_count(old_inode);
 346                        goto out_dir;
 347                }
 348                if (dir_de)
 349                        inode_inc_link_count(new_dir);
 350        }
 351
 352        /*
 353         * Like most other Unix systems, set the ctime for inodes on a
 354         * rename.
 355         * inode_dec_link_count() will mark the inode dirty.
 356         */
 357        old_inode->i_ctime = CURRENT_TIME_SEC;
 358
 359        ext2_delete_entry (old_de, old_page);
 360        inode_dec_link_count(old_inode);
 361
 362        if (dir_de) {
 363                if (old_dir != new_dir)
 364                        ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
 365                else {
 366                        kunmap(dir_page);
 367                        page_cache_release(dir_page);
 368                }
 369                inode_dec_link_count(old_dir);
 370        }
 371        return 0;
 372
 373
 374out_dir:
 375        if (dir_de) {
 376                kunmap(dir_page);
 377                page_cache_release(dir_page);
 378        }
 379out_old:
 380        kunmap(old_page);
 381        page_cache_release(old_page);
 382out:
 383        return err;
 384}
 385
 386const struct inode_operations ext2_dir_inode_operations = {
 387        .create         = ext2_create,
 388        .lookup         = ext2_lookup,
 389        .link           = ext2_link,
 390        .unlink         = ext2_unlink,
 391        .symlink        = ext2_symlink,
 392        .mkdir          = ext2_mkdir,
 393        .rmdir          = ext2_rmdir,
 394        .mknod          = ext2_mknod,
 395        .rename         = ext2_rename,
 396#ifdef CONFIG_EXT2_FS_XATTR
 397        .setxattr       = generic_setxattr,
 398        .getxattr       = generic_getxattr,
 399        .listxattr      = ext2_listxattr,
 400        .removexattr    = generic_removexattr,
 401#endif
 402        .setattr        = ext2_setattr,
 403        .check_acl      = ext2_check_acl,
 404};
 405
 406const struct inode_operations ext2_special_inode_operations = {
 407#ifdef CONFIG_EXT2_FS_XATTR
 408        .setxattr       = generic_setxattr,
 409        .getxattr       = generic_getxattr,
 410        .listxattr      = ext2_listxattr,
 411        .removexattr    = generic_removexattr,
 412#endif
 413        .setattr        = ext2_setattr,
 414        .check_acl      = ext2_check_acl,
 415};
 416