linux/fs/exofs/namei.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005, 2006
   3 * Avishay Traeger (avishay@gmail.com)
   4 * Copyright (C) 2008, 2009
   5 * Boaz Harrosh <bharrosh@panasas.com>
   6 *
   7 * Copyrights for code taken from ext2:
   8 *     Copyright (C) 1992, 1993, 1994, 1995
   9 *     Remy Card (card@masi.ibp.fr)
  10 *     Laboratoire MASI - Institut Blaise Pascal
  11 *     Universite Pierre et Marie Curie (Paris VI)
  12 *     from
  13 *     linux/fs/minix/inode.c
  14 *     Copyright (C) 1991, 1992  Linus Torvalds
  15 *
  16 * This file is part of exofs.
  17 *
  18 * exofs is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation.  Since it is based on ext2, and the only
  21 * valid version of GPL for the Linux kernel is version 2, the only valid
  22 * version of GPL for exofs is version 2.
  23 *
  24 * exofs is distributed in the hope that it will be useful,
  25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27 * GNU General Public License for more details.
  28 *
  29 * You should have received a copy of the GNU General Public License
  30 * along with exofs; if not, write to the Free Software
  31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  32 */
  33
  34#include "exofs.h"
  35
  36static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
  37{
  38        int err = exofs_add_link(dentry, inode);
  39        if (!err) {
  40                d_instantiate(dentry, inode);
  41                return 0;
  42        }
  43        inode_dec_link_count(inode);
  44        iput(inode);
  45        return err;
  46}
  47
  48static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
  49                                   struct nameidata *nd)
  50{
  51        struct inode *inode;
  52        ino_t ino;
  53
  54        if (dentry->d_name.len > EXOFS_NAME_LEN)
  55                return ERR_PTR(-ENAMETOOLONG);
  56
  57        ino = exofs_inode_by_name(dir, dentry);
  58        inode = NULL;
  59        if (ino) {
  60                inode = exofs_iget(dir->i_sb, ino);
  61                if (IS_ERR(inode))
  62                        return ERR_CAST(inode);
  63        }
  64        return d_splice_alias(inode, dentry);
  65}
  66
  67static int exofs_create(struct inode *dir, struct dentry *dentry, int mode,
  68                         struct nameidata *nd)
  69{
  70        struct inode *inode = exofs_new_inode(dir, mode);
  71        int err = PTR_ERR(inode);
  72        if (!IS_ERR(inode)) {
  73                inode->i_op = &exofs_file_inode_operations;
  74                inode->i_fop = &exofs_file_operations;
  75                inode->i_mapping->a_ops = &exofs_aops;
  76                mark_inode_dirty(inode);
  77                err = exofs_add_nondir(dentry, inode);
  78        }
  79        return err;
  80}
  81
  82static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
  83                       dev_t rdev)
  84{
  85        struct inode *inode;
  86        int err;
  87
  88        if (!new_valid_dev(rdev))
  89                return -EINVAL;
  90
  91        inode = exofs_new_inode(dir, mode);
  92        err = PTR_ERR(inode);
  93        if (!IS_ERR(inode)) {
  94                init_special_inode(inode, inode->i_mode, rdev);
  95                mark_inode_dirty(inode);
  96                err = exofs_add_nondir(dentry, inode);
  97        }
  98        return err;
  99}
 100
 101static int exofs_symlink(struct inode *dir, struct dentry *dentry,
 102                          const char *symname)
 103{
 104        struct super_block *sb = dir->i_sb;
 105        int err = -ENAMETOOLONG;
 106        unsigned l = strlen(symname)+1;
 107        struct inode *inode;
 108        struct exofs_i_info *oi;
 109
 110        if (l > sb->s_blocksize)
 111                goto out;
 112
 113        inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
 114        err = PTR_ERR(inode);
 115        if (IS_ERR(inode))
 116                goto out;
 117
 118        oi = exofs_i(inode);
 119        if (l > sizeof(oi->i_data)) {
 120                /* slow symlink */
 121                inode->i_op = &exofs_symlink_inode_operations;
 122                inode->i_mapping->a_ops = &exofs_aops;
 123                memset(oi->i_data, 0, sizeof(oi->i_data));
 124
 125                err = page_symlink(inode, symname, l);
 126                if (err)
 127                        goto out_fail;
 128        } else {
 129                /* fast symlink */
 130                inode->i_op = &exofs_fast_symlink_inode_operations;
 131                memcpy(oi->i_data, symname, l);
 132                inode->i_size = l-1;
 133        }
 134        mark_inode_dirty(inode);
 135
 136        err = exofs_add_nondir(dentry, inode);
 137out:
 138        return err;
 139
 140out_fail:
 141        inode_dec_link_count(inode);
 142        iput(inode);
 143        goto out;
 144}
 145
 146static int exofs_link(struct dentry *old_dentry, struct inode *dir,
 147                struct dentry *dentry)
 148{
 149        struct inode *inode = old_dentry->d_inode;
 150
 151        if (inode->i_nlink >= EXOFS_LINK_MAX)
 152                return -EMLINK;
 153
 154        inode->i_ctime = CURRENT_TIME;
 155        inode_inc_link_count(inode);
 156        atomic_inc(&inode->i_count);
 157
 158        return exofs_add_nondir(dentry, inode);
 159}
 160
 161static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 162{
 163        struct inode *inode;
 164        int err = -EMLINK;
 165
 166        if (dir->i_nlink >= EXOFS_LINK_MAX)
 167                goto out;
 168
 169        inode_inc_link_count(dir);
 170
 171        inode = exofs_new_inode(dir, S_IFDIR | mode);
 172        err = PTR_ERR(inode);
 173        if (IS_ERR(inode))
 174                goto out_dir;
 175
 176        inode->i_op = &exofs_dir_inode_operations;
 177        inode->i_fop = &exofs_dir_operations;
 178        inode->i_mapping->a_ops = &exofs_aops;
 179
 180        inode_inc_link_count(inode);
 181
 182        err = exofs_make_empty(inode, dir);
 183        if (err)
 184                goto out_fail;
 185
 186        err = exofs_add_link(dentry, inode);
 187        if (err)
 188                goto out_fail;
 189
 190        d_instantiate(dentry, inode);
 191out:
 192        return err;
 193
 194out_fail:
 195        inode_dec_link_count(inode);
 196        inode_dec_link_count(inode);
 197        iput(inode);
 198out_dir:
 199        inode_dec_link_count(dir);
 200        goto out;
 201}
 202
 203static int exofs_unlink(struct inode *dir, struct dentry *dentry)
 204{
 205        struct inode *inode = dentry->d_inode;
 206        struct exofs_dir_entry *de;
 207        struct page *page;
 208        int err = -ENOENT;
 209
 210        de = exofs_find_entry(dir, dentry, &page);
 211        if (!de)
 212                goto out;
 213
 214        err = exofs_delete_entry(de, page);
 215        if (err)
 216                goto out;
 217
 218        inode->i_ctime = dir->i_ctime;
 219        inode_dec_link_count(inode);
 220        err = 0;
 221out:
 222        return err;
 223}
 224
 225static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
 226{
 227        struct inode *inode = dentry->d_inode;
 228        int err = -ENOTEMPTY;
 229
 230        if (exofs_empty_dir(inode)) {
 231                err = exofs_unlink(dir, dentry);
 232                if (!err) {
 233                        inode->i_size = 0;
 234                        inode_dec_link_count(inode);
 235                        inode_dec_link_count(dir);
 236                }
 237        }
 238        return err;
 239}
 240
 241static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
 242                struct inode *new_dir, struct dentry *new_dentry)
 243{
 244        struct inode *old_inode = old_dentry->d_inode;
 245        struct inode *new_inode = new_dentry->d_inode;
 246        struct page *dir_page = NULL;
 247        struct exofs_dir_entry *dir_de = NULL;
 248        struct page *old_page;
 249        struct exofs_dir_entry *old_de;
 250        int err = -ENOENT;
 251
 252        old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
 253        if (!old_de)
 254                goto out;
 255
 256        if (S_ISDIR(old_inode->i_mode)) {
 257                err = -EIO;
 258                dir_de = exofs_dotdot(old_inode, &dir_page);
 259                if (!dir_de)
 260                        goto out_old;
 261        }
 262
 263        if (new_inode) {
 264                struct page *new_page;
 265                struct exofs_dir_entry *new_de;
 266
 267                err = -ENOTEMPTY;
 268                if (dir_de && !exofs_empty_dir(new_inode))
 269                        goto out_dir;
 270
 271                err = -ENOENT;
 272                new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
 273                if (!new_de)
 274                        goto out_dir;
 275                inode_inc_link_count(old_inode);
 276                err = exofs_set_link(new_dir, new_de, new_page, old_inode);
 277                new_inode->i_ctime = CURRENT_TIME;
 278                if (dir_de)
 279                        drop_nlink(new_inode);
 280                inode_dec_link_count(new_inode);
 281                if (err)
 282                        goto out_dir;
 283        } else {
 284                if (dir_de) {
 285                        err = -EMLINK;
 286                        if (new_dir->i_nlink >= EXOFS_LINK_MAX)
 287                                goto out_dir;
 288                }
 289                inode_inc_link_count(old_inode);
 290                err = exofs_add_link(new_dentry, old_inode);
 291                if (err) {
 292                        inode_dec_link_count(old_inode);
 293                        goto out_dir;
 294                }
 295                if (dir_de)
 296                        inode_inc_link_count(new_dir);
 297        }
 298
 299        old_inode->i_ctime = CURRENT_TIME;
 300
 301        exofs_delete_entry(old_de, old_page);
 302        inode_dec_link_count(old_inode);
 303
 304        if (dir_de) {
 305                err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
 306                inode_dec_link_count(old_dir);
 307                if (err)
 308                        goto out_dir;
 309        }
 310        return 0;
 311
 312
 313out_dir:
 314        if (dir_de) {
 315                kunmap(dir_page);
 316                page_cache_release(dir_page);
 317        }
 318out_old:
 319        kunmap(old_page);
 320        page_cache_release(old_page);
 321out:
 322        return err;
 323}
 324
 325const struct inode_operations exofs_dir_inode_operations = {
 326        .create         = exofs_create,
 327        .lookup         = exofs_lookup,
 328        .link           = exofs_link,
 329        .unlink         = exofs_unlink,
 330        .symlink        = exofs_symlink,
 331        .mkdir          = exofs_mkdir,
 332        .rmdir          = exofs_rmdir,
 333        .mknod          = exofs_mknod,
 334        .rename         = exofs_rename,
 335        .setattr        = exofs_setattr,
 336};
 337
 338const struct inode_operations exofs_special_inode_operations = {
 339        .setattr        = exofs_setattr,
 340};
 341