static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); ino = ext2_inode_by_name(dir, &dentry->d_name); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); <<<<<<< HEAD if (IS_ERR(inode)) { ======= if (unlikely(IS_ERR(inode))) { >>>>>>> 296c66da8a02d52243f45b80521febece5ed498a if (PTR_ERR(inode) == -ESTALE) { ext2_error(dir->i_sb, __func__, "deleted inode referenced: %lu", (unsigned long) ino); return ERR_PTR(-EIO); } else { return ERR_CAST(inode); } }
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); ino = ext2_inode_by_name(dir, &dentry->d_name); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); if (unlikely(IS_ERR(inode))) { if (PTR_ERR(inode) == -ESTALE) { ext2_error(dir->i_sb, __func__, "deleted inode referenced: %lu", (unsigned long) ino); return ERR_PTR(-EIO); } else { return ERR_CAST(inode); } } } return d_splice_alias(inode, dentry); }
struct dentry *ext2_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino)); }
// Vijay: Modified lookup for ext2bp. This includes a validation check inside it. static struct dentry *ext2bp_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { ext2bp_debug("Inside ext2bp_lookup for dir with inode num: %lu\n", dir->i_ino); struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); ino = ext2_inode_by_name(dir, dentry); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); // Check the inode state if (inode->i_state & I_DIRTY) ext2bp_debug("Inode's state: dirty\n"); if (inode->i_state & I_NEW) ext2bp_debug("Inode's state: new\n"); if (inode->i_state & I_LOCK) ext2bp_debug("Inode's state: locked\n"); if (inode->i_state & I_CLEAR) ext2bp_debug("Inode's state: clear\n"); if (inode->i_state & I_SYNC) ext2bp_debug("Inode's state: sync\n"); ext2bp_debug("Inode's state: something I didnt check for\n"); // Now that we have the child inode, we can // carry out the check. struct ext2_inode_info *ei = EXT2_I(inode); int n; int backlink_present = 0; for (n=0; n < EXT2_N_LINKS; n++) if (ei->i_backlinks[n] == dir->i_ino) { backlink_present = 1; ext2bp_debug("Found backlink from %lu to %lu\n", inode->i_ino, dir->i_ino); break; } if (!backlink_present) { printk("Vijay:Error:Did not find backlink from %lu to %lu\n", inode->i_ino, dir->i_ino); iput(inode); return ERR_PTR(-EIO); } } return d_splice_alias(inode, dentry); }
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); ino = ext2_inode_by_name(dir, dentry); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } return d_splice_alias(inode, dentry); }
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) { struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); ino = ext2_inode_by_name(dir, &dentry->d_name); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); if (inode == ERR_PTR(-ESTALE)) { ext2_error(dir->i_sb, __func__, "deleted inode referenced: %lu", (unsigned long) ino); return ERR_PTR(-EIO); } } return d_splice_alias(inode, dentry); }
struct dentry *ext2_get_parent(struct dentry *child) { unsigned long ino; struct dentry *parent; struct inode *inode; struct dentry dotdot; dotdot.d_name.name = ".."; dotdot.d_name.len = 2; ino = ext2_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); inode = iget(child->d_inode->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); parent = d_alloc_anon(inode); if (!parent) { iput(inode); parent = ERR_PTR(-ENOMEM); } return parent; }
struct dentry *ext2_get_parent(struct dentry *child) { struct qstr dotdot = {.name = "..", .len = 2}; unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino)); } /* * By the time this is called, we already have created * the directory cache entry for the new file, but it * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information * with d_instantiate(). */ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { struct inode *inode; dquot_initialize(dir); inode = ext2_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; if (ext2_use_xip(inode->i_sb)) { inode->i_mapping->a_ops = &ext2_aops_xip; inode->i_fop = &ext2_xip_file_operations; } else if (test_opt(inode->i_sb, NOBH)) { inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; } mark_inode_dirty(inode); return ext2_add_nondir(dentry, inode); } static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode * inode; int err; if (!new_valid_dev(rdev)) return -EINVAL; dquot_initialize(dir); inode = ext2_new_inode (dir, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); #ifdef CONFIG_EXT2_FS_XATTR inode->i_op = &ext2_special_inode_operations; #endif mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); } return err; } static int ext2_symlink (struct inode * dir, struct dentry * dentry, const char * symname) { struct super_block * sb = dir->i_sb; int err = -ENAMETOOLONG; unsigned l = strlen(symname)+1; struct inode * inode; if (l > sb->s_blocksize) goto out; dquot_initialize(dir); inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out; if (l > sizeof (EXT2_I(inode)->i_data)) { /* slow symlink */ inode->i_op = &ext2_symlink_inode_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; err = page_symlink(inode, symname, l); if (err) goto out_fail; } else { /* fast symlink */ inode->i_op = &ext2_fast_symlink_inode_operations; memcpy((char*)(EXT2_I(inode)->i_data),symname,l); inode->i_size = l-1; } mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); out: return err; out_fail: inode_dec_link_count(inode); unlock_new_inode(inode); iput (inode); goto out; } static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; int err; if (inode->i_nlink >= EXT2_LINK_MAX) return -EMLINK; dquot_initialize(dir); inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); ihold(inode); err = ext2_add_link(dentry, inode); if (!err) { d_instantiate(dentry, inode); return 0; } inode_dec_link_count(inode); iput(inode); return err; } static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) { struct inode * inode; int err = -EMLINK; if (dir->i_nlink >= EXT2_LINK_MAX) goto out; dquot_initialize(dir); inode_inc_link_count(dir); inode = ext2_new_inode (dir, S_IFDIR | mode); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_dir; inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; inode_inc_link_count(inode); err = ext2_make_empty(inode, dir); if (err) goto out_fail; err = ext2_add_link(dentry, inode); if (err) goto out_fail; d_instantiate(dentry, inode); unlock_new_inode(inode); out: return err; out_fail: inode_dec_link_count(inode); inode_dec_link_count(inode); unlock_new_inode(inode); iput(inode); out_dir: inode_dec_link_count(dir); goto out; } static int ext2_unlink(struct inode * dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; struct ext2_dir_entry_2 * de; struct page * page; int err = -ENOENT; dquot_initialize(dir); de = ext2_find_entry (dir, &dentry->d_name, &page); if (!de) goto out; err = ext2_delete_entry (de, page); if (err) goto out; inode->i_ctime = dir->i_ctime; inode_dec_link_count(inode); err = 0; out: return err; } static int ext2_rmdir (struct inode * dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; int err = -ENOTEMPTY; if (ext2_empty_dir(inode)) { err = ext2_unlink(dir, dentry); if (!err) { inode->i_size = 0; inode_dec_link_count(inode); inode_dec_link_count(dir); } } return err; } static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct page * dir_page = NULL; struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; struct ext2_dir_entry_2 * old_de; int err = -ENOENT; dquot_initialize(old_dir); dquot_initialize(new_dir); old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); if (!old_de) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; dir_de = ext2_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { struct page *new_page; struct ext2_dir_entry_2 *new_de; err = -ENOTEMPTY; if (dir_de && !ext2_empty_dir (new_inode)) goto out_dir; err = -ENOENT; new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); if (!new_de) goto out_dir; ext2_set_link(new_dir, new_de, new_page, old_inode, 1); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { if (dir_de) { err = -EMLINK; if (new_dir->i_nlink >= EXT2_LINK_MAX) goto out_dir; } err = ext2_add_link(new_dentry, old_inode); if (err) goto out_dir; if (dir_de) inode_inc_link_count(new_dir); } /* * Like most other Unix systems, set the ctime for inodes on a * rename. */ old_inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(old_inode); ext2_delete_entry (old_de, old_page); if (dir_de) { if (old_dir != new_dir) ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); else { kunmap(dir_page); page_cache_release(dir_page); } inode_dec_link_count(old_dir); } return 0; out_dir: if (dir_de) { kunmap(dir_page); page_cache_release(dir_page); } out_old: kunmap(old_page); page_cache_release(old_page); out: return err; } const struct inode_operations ext2_dir_inode_operations = { .create = ext2_create, .lookup = ext2_lookup, .link = ext2_link, .unlink = ext2_unlink, .symlink = ext2_symlink, .mkdir = ext2_mkdir, .rmdir = ext2_rmdir, .mknod = ext2_mknod, .rename = ext2_rename, #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, .check_acl = ext2_check_acl, }; const struct inode_operations ext2_special_inode_operations = { #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, .check_acl = ext2_check_acl, };