LCOV - code coverage report
Current view: top level - lkbce/fs/ext2 - namei.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 221 221 100.0 %
Date: 2017-01-25 Functions: 11 11 100.0 %

          Line data    Source code
       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             : 
      39             : static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
      40             : {
      41          72 :         int err = ext2_add_link(dentry, inode);
      42          36 :         if (!err) {
      43          12 :                 d_instantiate(dentry, inode);
      44          12 :                 unlock_new_inode(inode);
      45          12 :                 return 0;
      46             :         }
      47          24 :         inode_dec_link_count(inode);
      48          12 :         unlock_new_inode(inode);
      49          12 :         iput(inode);
      50          12 :         return err;
      51             : }
      52             : 
      53             : /*
      54             :  * Methods themselves.
      55             :  */
      56             : 
      57             : static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
      58             : {
      59           4 :         struct inode * inode;
      60           4 :         ino_t ino;
      61           4 :         
      62          12 :         if (dentry->d_name.len > EXT2_NAME_LEN)
      63          16 :                 return ERR_PTR(-ENAMETOOLONG);
      64           4 : 
      65          16 :         ino = ext2_inode_by_name(dir, &dentry->d_name);
      66           8 :         inode = NULL;
      67          12 :         if (ino) {
      68          20 :                 inode = ext2_iget(dir->i_sb, ino);
      69          24 :                 if (unlikely(IS_ERR(inode))) {
      70          16 :                         if (PTR_ERR(inode) == -ESTALE) {
      71          12 :                                 ext2_error(dir->i_sb, __func__,
      72             :                                                 "deleted inode referenced: %lu",
      73             :                                                 (unsigned long) ino);
      74          12 :                                 return ERR_PTR(-EIO);
      75             :                         } else {
      76          12 :                                 return ERR_CAST(inode);
      77             :                         }
      78             :                 }
      79             :         }
      80          16 :         return d_splice_alias(inode, dentry);
      81             : }
      82             : 
      83             : struct dentry *ext2_get_parent(struct dentry *child)
      84             : {
      85           4 :         struct qstr dotdot = {.name = "..", .len = 2};
      86           5 :         unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
      87           3 :         if (!ino)
      88           4 :                 return ERR_PTR(-ENOENT);
      89           8 :         return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino));
      90           1 : } 
      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             :  */
     100             : static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd)
     101             : {
     102          28 :         struct inode * inode = ext2_new_inode (dir, mode);
     103          16 :         int err = PTR_ERR(inode);
     104          20 :         if (!IS_ERR(inode)) {
     105           8 :                 inode->i_op = &ext2_file_inode_operations;
     106           4 :                 if (ext2_use_xip(inode->i_sb)) {
     107           4 :                         inode->i_mapping->a_ops = &ext2_aops_xip;
     108             :                         inode->i_fop = &ext2_xip_file_operations;
     109          16 :                 } else if (test_opt(inode->i_sb, NOBH)) {
     110           4 :                         inode->i_mapping->a_ops = &ext2_nobh_aops;
     111           4 :                         inode->i_fop = &ext2_file_operations;
     112             :                 } else {
     113           4 :                         inode->i_mapping->a_ops = &ext2_aops;
     114           4 :                         inode->i_fop = &ext2_file_operations;
     115             :                 }
     116           8 :                 mark_inode_dirty(inode);
     117          12 :                 err = ext2_add_nondir(dentry, inode);
     118             :         }
     119           8 :         return err;
     120             : }
     121             : 
     122             : static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
     123             : {
     124           4 :         struct inode * inode;
     125           4 :         int err;
     126           4 : 
     127          20 :         if (!new_valid_dev(rdev))
     128           8 :                 return -EINVAL;
     129             : 
     130          20 :         inode = ext2_new_inode (dir, mode);
     131          12 :         err = PTR_ERR(inode);
     132          16 :         if (!IS_ERR(inode)) {
     133           8 :                 init_special_inode(inode, inode->i_mode, rdev);
     134             : #ifdef CONFIG_EXT2_FS_XATTR
     135           4 :                 inode->i_op = &ext2_special_inode_operations;
     136             : #endif
     137           8 :                 mark_inode_dirty(inode);
     138          12 :                 err = ext2_add_nondir(dentry, inode);
     139             :         }
     140           8 :         return err;
     141             : }
     142             : 
     143             : static int ext2_symlink (struct inode * dir, struct dentry * dentry,
     144             :         const char * symname)
     145           4 : {
     146           8 :         struct super_block * sb = dir->i_sb;
     147           8 :         int err = -ENAMETOOLONG;
     148          12 :         unsigned l = strlen(symname)+1;
     149           4 :         struct inode * inode;
     150           4 : 
     151          12 :         if (l > sb->s_blocksize)
     152           8 :                 goto out;
     153           4 : 
     154          20 :         inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
     155          12 :         err = PTR_ERR(inode);
     156          16 :         if (IS_ERR(inode))
     157           4 :                 goto out;
     158             : 
     159           8 :         if (l > sizeof (EXT2_I(inode)->i_data)) {
     160             :                 /* slow symlink */
     161           4 :                 inode->i_op = &ext2_symlink_inode_operations;
     162          16 :                 if (test_opt(inode->i_sb, NOBH))
     163           4 :                         inode->i_mapping->a_ops = &ext2_nobh_aops;
     164             :                 else
     165           4 :                         inode->i_mapping->a_ops = &ext2_aops;
     166           4 :                 err = page_symlink(inode, symname, l);
     167           8 :                 if (err)
     168           4 :                         goto out_fail;
     169             :         } else {
     170             :                 /* fast symlink */
     171           4 :                 inode->i_op = &ext2_fast_symlink_inode_operations;
     172          12 :                 memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
     173           4 :                 inode->i_size = l-1;
     174             :         }
     175          16 :         mark_inode_dirty(inode);
     176             : 
     177          12 :         err = ext2_add_nondir(dentry, inode);
     178             : out:
     179          20 :         return err;
     180           4 : 
     181             : out_fail:
     182           8 :         inode_dec_link_count(inode);
     183           4 :         unlock_new_inode(inode);
     184           4 :         iput (inode);
     185           4 :         goto out;
     186             : }
     187             : 
     188             : static int ext2_link (struct dentry * old_dentry, struct inode * dir,
     189             :         struct dentry *dentry)
     190           4 : {
     191           8 :         struct inode *inode = old_dentry->d_inode;
     192           4 :         int err;
     193           4 : 
     194           8 :         if (inode->i_nlink >= EXT2_LINK_MAX)
     195           4 :                 return -EMLINK;
     196             : 
     197          16 :         inode->i_ctime = CURRENT_TIME_SEC;
     198           8 :         inode_inc_link_count(inode);
     199           8 :         atomic_inc(&inode->i_count);
     200             : 
     201          16 :         err = ext2_add_link(dentry, inode);
     202           8 :         if (!err) {
     203           4 :                 d_instantiate(dentry, inode);
     204           4 :                 return 0;
     205             :         }
     206           8 :         inode_dec_link_count(inode);
     207           4 :         iput(inode);
     208           4 :         return err;
     209             : }
     210             : 
     211             : static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
     212             : {
     213           4 :         struct inode * inode;
     214           8 :         int err = -EMLINK;
     215           4 : 
     216          12 :         if (dir->i_nlink >= EXT2_LINK_MAX)
     217           8 :                 goto out;
     218             : 
     219           8 :         inode_inc_link_count(dir);
     220             : 
     221          20 :         inode = ext2_new_inode (dir, S_IFDIR | mode);
     222          12 :         err = PTR_ERR(inode);
     223          16 :         if (IS_ERR(inode))
     224           4 :                 goto out_dir;
     225             : 
     226           4 :         inode->i_op = &ext2_dir_inode_operations;
     227           4 :         inode->i_fop = &ext2_dir_operations;
     228          16 :         if (test_opt(inode->i_sb, NOBH))
     229           4 :                 inode->i_mapping->a_ops = &ext2_nobh_aops;
     230             :         else
     231           4 :                 inode->i_mapping->a_ops = &ext2_aops;
     232             : 
     233           8 :         inode_inc_link_count(inode);
     234             : 
     235          16 :         err = ext2_make_empty(inode, dir);
     236           8 :         if (err)
     237           4 :                 goto out_fail;
     238             : 
     239          16 :         err = ext2_add_link(dentry, inode);
     240           8 :         if (err)
     241           4 :                 goto out_fail;
     242             : 
     243           4 :         d_instantiate(dentry, inode);
     244           4 :         unlock_new_inode(inode);
     245             : out:
     246          16 :         return err;
     247           8 : 
     248             : out_fail:
     249          16 :         inode_dec_link_count(inode);
     250           8 :         inode_dec_link_count(inode);
     251           4 :         unlock_new_inode(inode);
     252           4 :         iput(inode);
     253             : out_dir:
     254          20 :         inode_dec_link_count(dir);
     255           4 :         goto out;
     256             : }
     257             : 
     258             : static int ext2_unlink(struct inode * dir, struct dentry *dentry)
     259             : {
     260          16 :         struct inode * inode = dentry->d_inode;
     261           8 :         struct ext2_dir_entry_2 * de;
     262           8 :         struct page * page;
     263          16 :         int err = -ENOENT;
     264             : 
     265          48 :         de = ext2_find_entry (dir, &dentry->d_name, &page);
     266          16 :         if (!de)
     267           8 :                 goto out;
     268             : 
     269          16 :         err = ext2_delete_entry (de, page);
     270          16 :         if (err)
     271           8 :                 goto out;
     272             : 
     273           8 :         inode->i_ctime = dir->i_ctime;
     274          16 :         inode_dec_link_count(inode);
     275           8 :         err = 0;
     276             : out:
     277          32 :         return err;
     278             : }
     279             : 
     280             : static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
     281             : {
     282           8 :         struct inode * inode = dentry->d_inode;
     283           8 :         int err = -ENOTEMPTY;
     284           4 : 
     285          20 :         if (ext2_empty_dir(inode)) {
     286          16 :                 err = ext2_unlink(dir, dentry);
     287           8 :                 if (!err) {
     288           4 :                         inode->i_size = 0;
     289           8 :                         inode_dec_link_count(inode);
     290           8 :                         inode_dec_link_count(dir);
     291             :                 }
     292             :         }
     293          12 :         return err;
     294             : }
     295             : 
     296             : static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
     297             :         struct inode * new_dir, struct dentry * new_dentry )
     298             : {
     299           8 :         struct inode * old_inode = old_dentry->d_inode;
     300           8 :         struct inode * new_inode = new_dentry->d_inode;
     301           8 :         struct page * dir_page = NULL;
     302           8 :         struct ext2_dir_entry_2 * dir_de = NULL;
     303           4 :         struct page * old_page;
     304           4 :         struct ext2_dir_entry_2 * old_de;
     305           8 :         int err = -ENOENT;
     306           4 : 
     307          28 :         old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page);
     308          12 :         if (!old_de)
     309           8 :                 goto out;
     310           4 : 
     311          16 :         if (S_ISDIR(old_inode->i_mode)) {
     312           8 :                 err = -EIO;
     313          12 :                 dir_de = ext2_dotdot(old_inode, &dir_page);
     314           8 :                 if (!dir_de)
     315           4 :                         goto out_old;
     316             :         }
     317             : 
     318          16 :         if (new_inode) {
     319             :                 struct page *new_page;
     320             :                 struct ext2_dir_entry_2 *new_de;
     321             : 
     322           8 :                 err = -ENOTEMPTY;
     323          48 :                 if (dir_de && !ext2_empty_dir (new_inode))
     324           4 :                         goto out_dir;
     325             : 
     326          12 :                 err = -ENOENT;
     327          72 :                 new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
     328           8 :                 if (!new_de)
     329           4 :                         goto out_dir;
     330           8 :                 ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
     331          16 :                 new_inode->i_ctime = CURRENT_TIME_SEC;
     332           8 :                 if (dir_de)
     333           8 :                         drop_nlink(new_inode);
     334          16 :                 inode_dec_link_count(new_inode);
     335             :         } else {
     336          16 :                 if (dir_de) {
     337           8 :                         err = -EMLINK;
     338          16 :                         if (new_dir->i_nlink >= EXT2_LINK_MAX)
     339           8 :                                 goto out_dir;
     340             :                 }
     341          32 :                 err = ext2_add_link(new_dentry, old_inode);
     342           8 :                 if (err)
     343           4 :                         goto out_dir;
     344           8 :                 if (dir_de)
     345           8 :                         inode_inc_link_count(new_dir);
     346             :         }
     347             : 
     348             :         /*
     349             :          * Like most other Unix systems, set the ctime for inodes on a
     350             :          * rename.
     351             :          */
     352          48 :         old_inode->i_ctime = CURRENT_TIME_SEC;
     353          24 :         mark_inode_dirty(old_inode);
     354             : 
     355           8 :         ext2_delete_entry (old_de, old_page);
     356             : 
     357           8 :         if (dir_de) {
     358           8 :                 if (old_dir != new_dir)
     359           8 :                         ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
     360             :                 else {
     361           8 :                         kunmap(dir_page);
     362           4 :                         page_cache_release(dir_page);
     363             :                 }
     364          16 :                 inode_dec_link_count(old_dir);
     365             :         }
     366           8 :         return 0;
     367          20 : 
     368             : 
     369             : out_dir:
     370          40 :         if (dir_de) {
     371          40 :                 kunmap(dir_page);
     372           4 :                 page_cache_release(dir_page);
     373             :         }
     374             : out_old:
     375          48 :         kunmap(old_page);
     376           4 :         page_cache_release(old_page);
     377          24 : out:
     378          12 :         return err;
     379             : }
     380             : 
     381           1 : const struct inode_operations ext2_dir_inode_operations = {
     382             :         .create         = ext2_create,
     383             :         .lookup         = ext2_lookup,
     384             :         .link           = ext2_link,
     385             :         .unlink         = ext2_unlink,
     386             :         .symlink        = ext2_symlink,
     387             :         .mkdir          = ext2_mkdir,
     388             :         .rmdir          = ext2_rmdir,
     389             :         .mknod          = ext2_mknod,
     390             :         .rename         = ext2_rename,
     391             : #ifdef CONFIG_EXT2_FS_XATTR
     392             :         .setxattr       = generic_setxattr,
     393             :         .getxattr       = generic_getxattr,
     394             :         .listxattr      = ext2_listxattr,
     395             :         .removexattr    = generic_removexattr,
     396             : #endif
     397             :         .setattr        = ext2_setattr,
     398             :         .check_acl      = ext2_check_acl,
     399             : };
     400             : 
     401           1 : const struct inode_operations ext2_special_inode_operations = {
     402             : #ifdef CONFIG_EXT2_FS_XATTR
     403             :         .setxattr       = generic_setxattr,
     404             :         .getxattr       = generic_getxattr,
     405             :         .listxattr      = ext2_listxattr,
     406             :         .removexattr    = generic_removexattr,
     407             : #endif
     408             :         .setattr        = ext2_setattr,
     409             :         .check_acl      = ext2_check_acl,
     410             : };

Generated by: LCOV version 1.10