static int amfs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry *lower_dentry; struct inode *lower_dir_inode = amfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; /*************Check if trying to delete pattern file**************/ if (dentry->d_inode->i_ino == AMFS_SB(dentry->d_sb)->inode_no) { err = -EPERM; goto out_err; } /* here I am not allowing user to delete pattern db file. This will only * work if pattern db lies inside the directory which is being mounted */ /**********************XATTR ENDS HERE**************/ amfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = vfs_unlink(lower_dir_inode, lower_dentry, NULL); /* * Note: unlinking on top of NFS can cause silly-renamed files. * Trying to delete such files results in EBUSY from NFS * below. Silly-renamed files will get deleted by NFS later on, so * we just need to detect them here and treat such EBUSY errors as * if the upper file was successfully deleted. */ if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) err = 0; if (err) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); set_nlink(dentry->d_inode, amfs_lower_inode(dentry->d_inode)->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ out: unlock_dir(lower_dir_dentry); dput(lower_dentry); amfs_put_lower_path(dentry, &lower_path); out_err: return err; }
/* final actions when unmounting a file system */ static void amfs_put_super(struct super_block *sb) { struct amfs_sb_info *spd; struct super_block *s; struct pattern_item *temp_node = NULL; struct bad_file_item *mtemp_node = NULL; struct list_head *pos, *q; struct list_head *mpos, *mq; struct list_head *plist_head = NULL; spd = AMFS_SB(sb); if (!spd) return; plist_head = spd->pattern_list_head; list_for_each_safe(pos, q, plist_head) { temp_node = list_entry(pos, struct pattern_item, list); list_del(pos); kfree(temp_node); }
static int amfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err; struct path lower_old_path, lower_new_path; char *value = NULL; if (old_dentry->d_inode->i_ino == AMFS_SB(old_dentry->d_sb)->inode_no) { err = -EPERM; goto out_err; } /************XATTR************/ value = kzalloc(5, __GFP_WAIT); if (value == NULL) { err = -ENOMEM; goto out_err; } if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) > 0) { if (!strncmp(value, AMFS_BADFILE, 3)) { err = -EPERM; goto freevalue; } } else if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) != -ENODATA){ err = amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5); goto freevalue; } /************XATTR***********/ file_size_save = i_size_read(old_dentry->d_inode); amfs_get_lower_path(old_dentry, &lower_old_path); amfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry, NULL); if (err || !lower_new_dentry->d_inode) goto out; err = amfs_interpose(new_dentry, dir->i_sb, &lower_new_path); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, amfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: unlock_dir(lower_dir_dentry); amfs_put_lower_path(old_dentry, &lower_old_path); amfs_put_lower_path(new_dentry, &lower_new_path); freevalue: kfree(value); out_err: return err; }
/* * The locking rules in amfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int amfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; /*******Variable which will help in checking XATTR***************/ char *value = NULL; if (old_dentry->d_inode->i_ino == AMFS_SB(old_dentry->d_sb)->inode_no) { err = -EPERM; goto exitcode; } value = kzalloc(5, __GFP_WAIT); if (value == NULL) { err = -ENOMEM; goto exitcode; } if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) > 0) { if (!strncmp(value, AMFS_BADFILE, 3)) { err = -EPERM; goto freevalue; } } else if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) != -ENODATA) { err = amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5); goto freevalue; } /****************************************************************/ amfs_get_lower_path(old_dentry, &lower_old_path); amfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); amfs_put_lower_path(old_dentry, &lower_old_path); amfs_put_lower_path(new_dentry, &lower_new_path); freevalue: kfree(value); exitcode: return err; }