static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) { int retval; struct inode * inode; struct reiserfs_transaction_handle th ; int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; int locked; if (!new_valid_dev(rdev)) return -EINVAL; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM ; } retval = new_inode_init(inode, dir, mode); if (retval) return retval; locked = reiserfs_cache_default_acl (dir); reiserfs_write_lock(dir->i_sb); if (locked) reiserfs_write_lock_xattrs (dir->i_sb); journal_begin(&th, dir->i_sb, jbegin_count) ; retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode); if (locked) reiserfs_write_unlock_xattrs (dir->i_sb); if (retval) { goto out_failed; } inode->i_op = &reiserfs_special_inode_operations; init_special_inode(inode, inode->i_mode, rdev) ; //FIXME: needed for block and char devices only reiserfs_update_sd (&th, inode); reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(dir) ; retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1/*visible*/); if (retval) { inode->i_nlink--; reiserfs_update_sd (&th, inode); journal_end(&th, dir->i_sb, jbegin_count) ; iput (inode); goto out_failed; } d_instantiate(dentry, inode); journal_end(&th, dir->i_sb, jbegin_count) ; out_failed: reiserfs_write_unlock(dir->i_sb); return retval; }
static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) { if (inode && obj) { __u32 mode = obj->yst_mode; switch( obj->variantType ){ case YAFFS_OBJECT_TYPE_FILE : if( ! S_ISREG(mode) ){ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFREG; } break; case YAFFS_OBJECT_TYPE_SYMLINK : if( ! S_ISLNK(mode) ){ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFLNK; } break; case YAFFS_OBJECT_TYPE_DIRECTORY : if( ! S_ISDIR(mode) ){ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFDIR; } break; case YAFFS_OBJECT_TYPE_UNKNOWN : case YAFFS_OBJECT_TYPE_HARDLINK : case YAFFS_OBJECT_TYPE_SPECIAL : default: break; } inode->i_ino = obj->objectId; inode->i_mode = obj->yst_mode; inode->i_uid = obj->yst_uid; inode->i_gid = obj->yst_gid; inode->i_blksize = inode->i_sb->s_blocksize; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) inode->i_rdev = old_decode_dev(obj->yst_rdev); inode->i_atime.tv_sec = (time_t) (obj->yst_atime); inode->i_atime.tv_nsec = 0; inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; inode->i_mtime.tv_nsec = 0; inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; inode->i_ctime.tv_nsec = 0; #else inode->i_rdev = obj->yst_rdev; inode->i_atime = obj->yst_atime; inode->i_mtime = obj->yst_mtime; inode->i_ctime = obj->yst_ctime; #endif inode->i_size = yaffs_GetObjectFileLength(obj); inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_nlink = yaffs_GetObjectLinkCount(obj); T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", inode->i_mode, inode->i_uid, inode->i_gid, (int)inode->i_size, atomic_read(&inode->i_count))); switch (obj->yst_mode & S_IFMT) { default: #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) init_special_inode(inode, obj->yst_mode, old_decode_dev(obj->yst_rdev)); #else init_special_inode(inode, obj->yst_mode, (dev_t) (obj->yst_rdev)); #endif break; case S_IFREG: inode->i_op = &yaffs_file_inode_operations; inode->i_fop = &yaffs_file_operations; inode->i_mapping->a_ops = &yaffs_file_address_operations; break; case S_IFDIR: inode->i_op = &yaffs_dir_inode_operations; inode->i_fop = &yaffs_dir_operations; break; case S_IFLNK: inode->i_op = &yaffs_symlink_inode_operations; break; } inode->u.generic_ip = obj; obj->myInode = inode; } else {
struct inode *efs_iget(struct super_block *super, unsigned long ino) { int i, inode_index; dev_t device; u32 rdev; struct buffer_head *bh; struct efs_sb_info *sb = SUPER_INFO(super); struct efs_inode_info *in; efs_block_t block, offset; struct efs_dinode *efs_inode; struct inode *inode; inode = iget_locked(super, ino); if (IS_ERR(inode)) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; in = INODE_INFO(inode); /* ** EFS layout: ** ** | cylinder group | cylinder group | cylinder group ..etc ** |inodes|data |inodes|data |inodes|data ..etc ** ** work out the inode block index, (considering initially that the ** inodes are stored as consecutive blocks). then work out the block ** number of that inode given the above layout, and finally the ** offset of the inode within that block. */ inode_index = inode->i_ino / (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); block = sb->fs_start + sb->first_block + (sb->group_size * (inode_index / sb->inode_blocks)) + (inode_index % sb->inode_blocks); offset = (inode->i_ino % (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) * sizeof(struct efs_dinode); bh = sb_bread(inode->i_sb, block); if (!bh) { printk(KERN_WARNING "EFS: bread() failed at block %d\n", block); goto read_inode_error; } efs_inode = (struct efs_dinode *) (bh->b_data + offset); inode->i_mode = be16_to_cpu(efs_inode->di_mode); inode->i_nlink = be16_to_cpu(efs_inode->di_nlink); inode->i_uid = (uid_t)be16_to_cpu(efs_inode->di_uid); inode->i_gid = (gid_t)be16_to_cpu(efs_inode->di_gid); inode->i_size = be32_to_cpu(efs_inode->di_size); inode->i_atime.tv_sec = be32_to_cpu(efs_inode->di_atime); inode->i_mtime.tv_sec = be32_to_cpu(efs_inode->di_mtime); inode->i_ctime.tv_sec = be32_to_cpu(efs_inode->di_ctime); inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; /* this is the number of blocks in the file */ if (inode->i_size == 0) { inode->i_blocks = 0; } else { inode->i_blocks = ((inode->i_size - 1) >> EFS_BLOCKSIZE_BITS) + 1; } rdev = be16_to_cpu(efs_inode->di_u.di_dev.odev); if (rdev == 0xffff) { rdev = be32_to_cpu(efs_inode->di_u.di_dev.ndev); if (sysv_major(rdev) > 0xfff) device = 0; else device = MKDEV(sysv_major(rdev), sysv_minor(rdev)); } else device = old_decode_dev(rdev); /* get the number of extents for this object */ in->numextents = be16_to_cpu(efs_inode->di_numextents); in->lastextent = 0; /* copy the extents contained within the inode to memory */ for(i = 0; i < EFS_DIRECTEXTENTS; i++) { extent_copy(&(efs_inode->di_u.di_extents[i]), &(in->extents[i])); if (i < in->numextents && in->extents[i].cooked.ex_magic != 0) { printk(KERN_WARNING "EFS: extent %d has bad magic number in inode %lu\n", i, inode->i_ino); brelse(bh); goto read_inode_error; } } brelse(bh); #ifdef DEBUG printk(KERN_DEBUG "EFS: efs_iget(): inode %lu, extents %d, mode %o\n", inode->i_ino, in->numextents, inode->i_mode); #endif switch (inode->i_mode & S_IFMT) { case S_IFDIR: inode->i_op = &efs_dir_inode_operations; inode->i_fop = &efs_dir_operations; break; case S_IFREG: inode->i_fop = &generic_ro_fops; inode->i_data.a_ops = &efs_aops; break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; inode->i_data.a_ops = &efs_symlink_aops; break; case S_IFCHR: case S_IFBLK: case S_IFIFO: init_special_inode(inode, inode->i_mode, device); break; default: printk(KERN_WARNING "EFS: unsupported inode mode %o\n", inode->i_mode); goto read_inode_error; break; } unlock_new_inode(inode); return inode; read_inode_error: printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino); iget_failed(inode); return ERR_PTR(-EIO); }
void jffs2_read_inode (struct inode *inode) { struct jffs2_inode_info *f; struct jffs2_sb_info *c; struct jffs2_raw_inode latest_node; int ret; D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); f = JFFS2_INODE_INFO(inode); c = JFFS2_SB_INFO(inode->i_sb); jffs2_init_inode_info(f); down(&f->sem); ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); if (ret) { make_bad_inode(inode); up(&f->sem); return; } inode->i_mode = jemode_to_cpu(latest_node.mode); inode->i_uid = je16_to_cpu(latest_node.uid); inode->i_gid = je16_to_cpu(latest_node.gid); inode->i_size = je32_to_cpu(latest_node.isize); inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); inode->i_nlink = f->inocache->nlink; inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { jint16_t rdev; case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; break; case S_IFDIR: { struct jffs2_full_dirent *fd; for (fd=f->dents; fd; fd = fd->next) { if (fd->type == DT_DIR && fd->ino) inode->i_nlink++; } /* and '..' */ inode->i_nlink++; /* Root dir gets i_nlink 3 for some reason */ if (inode->i_ino == 1) inode->i_nlink++; inode->i_op = &jffs2_dir_inode_operations; inode->i_fop = &jffs2_dir_operations; break; } case S_IFREG: inode->i_op = &jffs2_file_inode_operations; inode->i_fop = &jffs2_file_operations; inode->i_mapping->a_ops = &jffs2_file_address_operations; inode->i_mapping->nrpages = 0; break; case S_IFBLK: case S_IFCHR: /* Read the device numbers from the media */ D1(printk(KERN_DEBUG "Reading device numbers from flash\n")); if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { /* Eep */ printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); up(&f->sem); jffs2_do_clear_inode(c, f); make_bad_inode(inode); return; } case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs2_file_inode_operations; init_special_inode(inode, inode->i_mode, old_decode_dev((je16_to_cpu(rdev)))); break; default: printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); } up(&f->sem); D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); }
/* * Initialize the Linux inode, set up the operation vectors and * unlock the inode. * * When reading existing inodes from disk this is called directly * from xfs_iget, when creating a new inode it is called from * xfs_ialloc after setting up the inode. * * We are always called with an uninitialised linux inode here. * We need to initialise the necessary fields and take a reference * on it. */ void xfs_setup_inode( struct xfs_inode *ip) { struct inode *inode = &ip->i_vnode; inode->i_ino = ip->i_ino; inode->i_state = I_NEW; inode_sb_list_add(inode); /* make the inode look hashed for the writeback code */ hlist_add_fake(&inode->i_hash); inode->i_mode = ip->i_d.di_mode; inode->i_nlink = ip->i_d.di_nlink; inode->i_uid = ip->i_d.di_uid; inode->i_gid = ip->i_d.di_gid; switch (inode->i_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: inode->i_rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, sysv_minor(ip->i_df.if_u2.if_rdev)); break; default: inode->i_rdev = 0; break; } inode->i_generation = ip->i_d.di_gen; i_size_write(inode, ip->i_d.di_size); inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; xfs_diflags_to_iflags(inode, ip); switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_op = &xfs_inode_operations; inode->i_fop = &xfs_file_operations; inode->i_mapping->a_ops = &xfs_address_space_operations; break; case S_IFDIR: if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) inode->i_op = &xfs_dir_ci_inode_operations; else inode->i_op = &xfs_dir_inode_operations; inode->i_fop = &xfs_dir_file_operations; break; case S_IFLNK: inode->i_op = &xfs_symlink_inode_operations; if (!(ip->i_df.if_flags & XFS_IFINLINE)) inode->i_mapping->a_ops = &xfs_address_space_operations; break; default: inode->i_op = &xfs_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } xfs_iflags_clear(ip, XFS_INEW); barrier(); unlock_new_inode(inode); }
static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) { int retval; struct inode * inode; struct reiserfs_transaction_handle th ; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); int locked; if (!new_valid_dev(rdev)) return -EINVAL; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM ; } new_inode_init(inode, dir, mode); locked = reiserfs_cache_default_acl (dir); reiserfs_write_lock(dir->i_sb); if (locked) reiserfs_write_lock_xattrs (dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count) ; if (retval) { drop_new_inode (inode); goto out_failed; } retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode); if (retval) { goto out_failed; } if (locked) { reiserfs_write_unlock_xattrs (dir->i_sb); locked = 0; } inode->i_op = &reiserfs_special_inode_operations; init_special_inode(inode, inode->i_mode, rdev) ; //FIXME: needed for block and char devices only reiserfs_update_sd (&th, inode); reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(dir) ; retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1/*visible*/); if (retval) { int err; inode->i_nlink--; reiserfs_update_sd (&th, inode); err = journal_end(&th, dir->i_sb, jbegin_count) ; if (err) retval = err; iput (inode); goto out_failed; } d_instantiate(dentry, inode); retval = journal_end(&th, dir->i_sb, jbegin_count) ; out_failed: if (locked) reiserfs_write_unlock_xattrs (dir->i_sb); reiserfs_write_unlock(dir->i_sb); return retval; }
struct dentry *f2fs_get_parent(struct dentry *child) { struct qstr dotdot = {.len = 2, .name = ".."}; unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); } static int __recover_dot_dentries(struct inode *dir, nid_t pino) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct qstr dot = {.len = 1, .name = "."}; struct qstr dotdot = {.len = 2, .name = ".."}; struct f2fs_dir_entry *de; struct page *page; int err = 0; f2fs_lock_op(sbi); de = f2fs_find_entry(dir, &dot, &page, 0); if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } else { err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); if (err) goto out; } de = f2fs_find_entry(dir, &dotdot, &page, 0); if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } else { err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); } out: if (!err) { clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); mark_inode_dirty(dir); } f2fs_unlock_op(sbi); return err; } static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct f2fs_dir_entry *de; struct page *page; nid_t ino; int err = 0; if (dentry->d_name.len > F2FS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); de = f2fs_find_entry(dir, &dentry->d_name, &page, nd ? nd->flags : 0); if (!de) return d_splice_alias(inode, dentry); ino = le32_to_cpu(de->ino); f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); inode = f2fs_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); if (f2fs_has_inline_dots(inode)) { err = __recover_dot_dentries(inode, dir->i_ino); if (err) goto err_out; } return d_splice_alias(inode, dentry); err_out: iget_failed(inode); return ERR_PTR(err); } static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode = dentry->d_inode; struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; trace_f2fs_unlink_enter(dir, dentry); f2fs_balance_fs(sbi); de = f2fs_find_entry(dir, &dentry->d_name, &page, 0); if (!de) goto fail; f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); if (err) { f2fs_unlock_op(sbi); f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); goto fail; } f2fs_delete_entry(de, page, dir, inode); f2fs_unlock_op(sbi); /* In order to evict this inode, we set it dirty */ mark_inode_dirty(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); fail: trace_f2fs_unlink_exit(inode, err); return err; } static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page; page = page_follow_link_light(dentry, nd); if (IS_ERR(page)) return page; /* this is broken symlink case */ if (*nd_get_link(nd) == 0) { kunmap(page); page_cache_release(page); return ERR_PTR(-ENOENT); } return page; } static int f2fs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; size_t len = strlen(symname); size_t p_len; char *p_str; struct f2fs_str disk_link = FSTR_INIT(NULL, 0); struct f2fs_encrypted_symlink_data *sd = NULL; int err; if (len > dir->i_sb->s_blocksize) return -ENAMETOOLONG; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) return PTR_ERR(inode); if (f2fs_encrypted_inode(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); if (f2fs_encrypted_inode(dir)) { struct qstr istr = QSTR_INIT(symname, len); err = f2fs_get_encryption_info(inode); if (err) goto err_out; err = f2fs_fname_crypto_alloc_buffer(inode, len, &disk_link); if (err) goto err_out; err = f2fs_fname_usr_to_disk(inode, &istr, &disk_link); if (err < 0) goto err_out; p_len = encrypted_symlink_data_len(disk_link.len) + 1; if (p_len > dir->i_sb->s_blocksize) { err = -ENAMETOOLONG; goto err_out; } sd = kzalloc(p_len, GFP_NOFS); if (!sd) { err = -ENOMEM; goto err_out; } memcpy(sd->encrypted_path, disk_link.name, disk_link.len); sd->len = cpu_to_le16(disk_link.len); p_str = (char *)sd; } else { p_len = len + 1; p_str = (char *)symname; } err = page_symlink(inode, p_str, p_len); err_out: d_instantiate(dentry, inode); unlock_new_inode(inode); /* * Let's flush symlink data in order to avoid broken symlink as much as * possible. Nevertheless, fsyncing is the best way, but there is no * way to get a file descriptor in order to flush that. * * Note that, it needs to do dir->fsync to make this recoverable. * If the symlink path is stored into inline_data, there is no * performance regression. */ if (!err) filemap_write_and_wait_range(inode->i_mapping, 0, p_len - 1); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); kfree(sd); f2fs_fname_crypto_free_buffer(&disk_link); return err; out: handle_failed_inode(inode); return err; } static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); set_inode_flag(F2FS_I(inode), FI_INC_LINK); f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out_fail; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); return 0; out_fail: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); handle_failed_inode(inode); return err; } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; if (f2fs_empty_dir(inode)) return f2fs_unlink(dir, dentry); return -ENOTEMPTY; } static int f2fs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err = 0; if (!new_valid_dev(rdev)) return -EINVAL; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &f2fs_special_inode_operations; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); return 0; out: handle_failed_inode(inode); return err; } static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct page *old_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; int err = -ENOENT; if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) && !f2fs_is_child_context_consistent_with_parent(new_dir, old_inode)) { err = -EPERM; goto out; } f2fs_balance_fs(sbi); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page, 0); if (!old_entry) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); if (!old_dir_entry) goto out_old; } if (new_inode) { err = -ENOTEMPTY; if (old_dir_entry && !f2fs_empty_dir(new_inode)) goto out_dir; err = -ENOENT; new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page, 0); if (!new_entry) goto out_dir; f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); if (err) goto put_out_dir; if (update_dent_inode(old_inode, new_inode, &new_dentry->d_name)) { release_orphan_inode(sbi); goto put_out_dir; } f2fs_set_link(new_dir, new_entry, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME; down_write(&F2FS_I(new_inode)->i_sem); if (old_dir_entry) drop_nlink(new_inode); drop_nlink(new_inode); up_write(&F2FS_I(new_inode)->i_sem); mark_inode_dirty(new_inode); if (!new_inode->i_nlink) add_orphan_inode(sbi, new_inode->i_ino); else release_orphan_inode(sbi); update_inode_page(old_inode); update_inode_page(new_inode); } else { f2fs_lock_op(sbi); err = f2fs_add_link(new_dentry, old_inode); if (err) { f2fs_unlock_op(sbi); goto out_dir; } if (old_dir_entry) { inc_nlink(new_dir); update_inode_page(new_dir); } } down_write(&F2FS_I(old_inode)->i_sem); file_lost_pino(old_inode); if (new_inode && file_enc_name(new_inode)) file_set_enc_name(old_inode); up_write(&F2FS_I(old_inode)->i_sem); old_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(old_inode); f2fs_delete_entry(old_entry, old_page, old_dir, NULL); if (old_dir_entry) { if (old_dir != new_dir) { f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); update_inode_page(old_inode); } else { f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } drop_nlink(old_dir); mark_inode_dirty(old_dir); update_inode_page(old_dir); } f2fs_unlock_op(sbi); if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) f2fs_sync_fs(sbi->sb, 1); return 0; put_out_dir: f2fs_unlock_op(sbi); f2fs_dentry_kunmap(new_dir, new_page); f2fs_put_page(new_page, 0); out_dir: if (old_dir_entry) { f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } out_old: f2fs_dentry_kunmap(old_dir, old_page); f2fs_put_page(old_page, 0); out: return err; } #ifdef CONFIG_F2FS_FS_ENCRYPTION static void *f2fs_encrypted_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *cpage = NULL; char *caddr, *paddr = NULL; struct f2fs_str cstr; struct f2fs_str pstr = FSTR_INIT(NULL, 0); struct inode *inode = dentry->d_inode; struct f2fs_encrypted_symlink_data *sd; loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); u32 max_size = inode->i_sb->s_blocksize; int res; res = f2fs_get_encryption_info(inode); if (res) return ERR_PTR(res); cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return cpage; caddr = kmap(cpage); caddr[size] = 0; /* Symlink is encrypted */ sd = (struct f2fs_encrypted_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); /* this is broken symlink case */ if (cstr.name[0] == 0 && cstr.len == 0) { res = -ENOENT; goto errout; } if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EIO; goto errout; } res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr); if (res) goto errout; res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr); if (res < 0) goto errout; paddr = pstr.name; /* Null-terminate the name */ paddr[res] = '\0'; nd_set_link(nd, paddr); kunmap(cpage); page_cache_release(cpage); return NULL; errout: f2fs_fname_crypto_free_buffer(&pstr); kunmap(cpage); page_cache_release(cpage); return ERR_PTR(res); } void kfree_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); } const struct inode_operations f2fs_encrypted_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = f2fs_encrypted_follow_link, .put_link = kfree_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, }; #endif const struct inode_operations f2fs_dir_inode_operations = { .create = f2fs_create, .lookup = f2fs_lookup, .link = f2fs_link, .unlink = f2fs_unlink, .symlink = f2fs_symlink, .mkdir = f2fs_mkdir, .rmdir = f2fs_rmdir, .mknod = f2fs_mknod, .rename = f2fs_rename, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .check_acl = f2fs_check_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = f2fs_follow_link, .put_link = page_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_special_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .check_acl = f2fs_check_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif };
static int set_inode(struct inode *inode, struct dentry *dentry) { int err; unsigned int flags; umode_t mode; aufs_bindex_t bindex, bstart, btail; unsigned char isdir; struct dentry *h_dentry; struct inode *h_inode; struct au_iinfo *iinfo; IiMustWriteLock(inode); err = 0; isdir = 0; bstart = au_dbstart(dentry); h_inode = au_h_dptr(dentry, bstart)->d_inode; mode = h_inode->i_mode; switch (mode & S_IFMT) { case S_IFREG: btail = au_dbtail(dentry); inode->i_op = &aufs_iop; inode->i_fop = &aufs_file_fop; inode->i_mapping->a_ops = &aufs_aop; break; case S_IFDIR: isdir = 1; btail = au_dbtaildir(dentry); inode->i_op = &aufs_dir_iop; inode->i_fop = &aufs_dir_fop; break; case S_IFLNK: btail = au_dbtail(dentry); inode->i_op = &aufs_symlink_iop; break; case S_IFBLK: case S_IFCHR: case S_IFIFO: case S_IFSOCK: btail = au_dbtail(dentry); inode->i_op = &aufs_iop; init_special_inode(inode, mode, h_inode->i_rdev); break; default: AuIOErr("Unknown file type 0%o\n", mode); err = -EIO; goto out; } /* do not set inotify for whiteouted dirs (SHWH mode) */ flags = au_hi_flags(inode, isdir); if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) && au_ftest_hi(flags, HINOTIFY) && dentry->d_name.len > AUFS_WH_PFX_LEN && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) au_fclr_hi(flags, HINOTIFY); iinfo = au_ii(inode); iinfo->ii_bstart = bstart; iinfo->ii_bend = btail; for (bindex = bstart; bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (h_dentry) au_set_h_iptr(inode, bindex, au_igrab(h_dentry->d_inode), flags); } au_cpup_attr_all(inode, /*force*/1); out: return err; }
static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { int retval; struct inode *inode; struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; /* * We need blocks for transaction + (user+group)*(quotas * for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); retval = dquot_initialize(dir); if (retval) return retval; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } retval = new_inode_init(inode, dir, mode); if (retval) { drop_new_inode(inode); return retval; } jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); if (retval < 0) { drop_new_inode(inode); return retval; } jbegin_count += retval; reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); goto out_failed; } retval = reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, inode, &security); if (retval) { goto out_failed; } inode->i_op = &reiserfs_special_inode_operations; init_special_inode(inode, inode->i_mode, rdev); /* FIXME: needed for block and char devices only */ reiserfs_update_sd(&th, inode); reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); retval = reiserfs_add_entry(&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1 /*visible */ ); if (retval) { int err; drop_nlink(inode); reiserfs_update_sd(&th, inode); err = journal_end(&th); if (err) retval = err; unlock_new_inode(inode); iput(inode); goto out_failed; } d_instantiate_new(dentry, inode); retval = journal_end(&th); out_failed: reiserfs_write_unlock(dir->i_sb); return retval; }
struct dentry *f2fs_get_parent(struct dentry *child) { struct qstr dotdot = {.len = 2, .name = ".."}; unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); } static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct f2fs_dir_entry *de; struct page *page; if (dentry->d_name.len > F2FS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); de = f2fs_find_entry(dir, &dentry->d_name, &page); if (de) { nid_t ino = le32_to_cpu(de->ino); kunmap(page); f2fs_put_page(page, 0); inode = f2fs_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } return d_splice_alias(inode, dentry); } static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode = dentry->d_inode; struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; trace_f2fs_unlink_enter(dir, dentry); f2fs_balance_fs(sbi); de = f2fs_find_entry(dir, &dentry->d_name, &page); if (!de) goto fail; f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); if (err) { f2fs_unlock_op(sbi); kunmap(page); f2fs_put_page(page, 0); goto fail; } f2fs_delete_entry(de, page, inode); f2fs_unlock_op(sbi); /* In order to evict this inode, we set it dirty */ mark_inode_dirty(inode); fail: trace_f2fs_unlink_exit(inode, err); return err; } static int f2fs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct super_block *sb = dir->i_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; size_t symlen = strlen(symname) + 1; int err; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); f2fs_unlock_op(sbi); if (err) goto out; err = page_symlink(inode, symname, symlen); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); return err; out: clear_nlink(inode); unlock_new_inode(inode); make_bad_inode(inode); iput(inode); alloc_nid_failed(sbi, inode->i_ino); return err; } static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct f2fs_sb_info *sbi; struct inode *inode; int err; if (dir->i_nlink >= F2FS_LINK_MAX) return -EMLINK; sbi = F2FS_SB(dir->i_sb); f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); set_inode_flag(F2FS_I(inode), FI_INC_LINK); f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); f2fs_unlock_op(sbi); if (err) goto out_fail; alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; out_fail: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); clear_nlink(inode); unlock_new_inode(inode); make_bad_inode(inode); iput(inode); alloc_nid_failed(sbi, inode->i_ino); return err; } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; if (f2fs_empty_dir(inode)) return f2fs_unlink(dir, dentry); return -ENOTEMPTY; } static int f2fs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct super_block *sb = dir->i_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; int err = 0; if (!new_valid_dev(rdev)) return -EINVAL; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &f2fs_special_inode_operations; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); f2fs_unlock_op(sbi); if (err) goto out; alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; out: clear_nlink(inode); unlock_new_inode(inode); make_bad_inode(inode); iput(inode); alloc_nid_failed(sbi, inode->i_ino); return err; } static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct super_block *sb = old_dir->i_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct page *old_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; int err = -ENOENT; f2fs_balance_fs(sbi); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_entry) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); if (!old_dir_entry) goto out_old; } f2fs_lock_op(sbi); if (new_inode) { err = -ENOTEMPTY; if (old_dir_entry && !f2fs_empty_dir(new_inode)) goto out_dir; err = -ENOENT; new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page); if (!new_entry) goto out_dir; err = acquire_orphan_inode(sbi); if (err) goto put_out_dir; if (update_dent_inode(old_inode, &new_dentry->d_name)) { release_orphan_inode(sbi); goto put_out_dir; } f2fs_set_link(new_dir, new_entry, new_page, old_inode); F2FS_I(old_inode)->i_pino = new_dir->i_ino; new_inode->i_ctime = CURRENT_TIME; if (old_dir_entry) drop_nlink(new_inode); drop_nlink(new_inode); mark_inode_dirty(new_inode); if (!new_inode->i_nlink) add_orphan_inode(sbi, new_inode->i_ino); else release_orphan_inode(sbi); update_inode_page(old_inode); update_inode_page(new_inode); } else { if (old_dir_entry) { err = -EMLINK; if (new_dir->i_nlink >= F2FS_LINK_MAX) goto out_dir; } err = f2fs_add_link(new_dentry, old_inode); if (err) goto out_dir; if (old_dir_entry) { inc_nlink(new_dir); update_inode_page(new_dir); } } old_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(old_inode); f2fs_delete_entry(old_entry, old_page, NULL); if (old_dir_entry) { if (old_dir != new_dir) { f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); F2FS_I(old_inode)->i_pino = new_dir->i_ino; update_inode_page(old_inode); } else { kunmap(old_dir_page); f2fs_put_page(old_dir_page, 0); } drop_nlink(old_dir); mark_inode_dirty(old_dir); update_inode_page(old_dir); } f2fs_unlock_op(sbi); return 0; put_out_dir: f2fs_put_page(new_page, 1); out_dir: if (old_dir_entry) { kunmap(old_dir_page); f2fs_put_page(old_dir_page, 0); } f2fs_unlock_op(sbi); out_old: kunmap(old_page); f2fs_put_page(old_page, 0); out: return err; } const struct inode_operations f2fs_dir_inode_operations = { .create = f2fs_create, .lookup = f2fs_lookup, .link = f2fs_link, .unlink = f2fs_unlink, .symlink = f2fs_symlink, .mkdir = f2fs_mkdir, .rmdir = f2fs_rmdir, .mknod = f2fs_mknod, .rename = f2fs_rename, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .check_acl = f2fs_check_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_special_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .check_acl = f2fs_check_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif };
static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct inode *inode; struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .dirtied_ino = 1 }; struct ubifs_inode *dir_ui = ubifs_inode(dir); /* * Budget request settings: new inode, new direntry, changing the * parent directory inode. */ dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); ubifs_err(c, "cannot create regular file, error %d", err); return err; } static int do_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode, struct inode **whiteout) { struct inode *inode; struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1}; struct ubifs_budget_req ino_req = { .dirtied_ino = 1 }; struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir); int err, instantiated = 0; /* * Budget request settings: new dirty inode, new direntry, * budget for dirtied inode will be released via writeback. */ dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; err = ubifs_budget_space(c, &ino_req); if (err) { ubifs_release_budget(c, &req); return err; } inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } ui = ubifs_inode(inode); if (whiteout) { init_special_inode(inode, inode->i_mode, WHITEOUT_DEV); ubifs_assert(inode->i_op == &ubifs_file_inode_operations); } err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&ui->ui_mutex); insert_inode_hash(inode); if (whiteout) { mark_inode_dirty(inode); drop_nlink(inode); *whiteout = inode; } else { d_tmpfile(dentry, inode); } ubifs_assert(ui->dirty); instantiated = 1; mutex_unlock(&ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex); err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); return 0; out_cancel: mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); if (!instantiated) iput(inode); out_budg: ubifs_release_budget(c, &req); if (!instantiated) ubifs_release_budget(c, &ino_req); ubifs_err(c, "cannot create temporary file, error %d", err); return err; } static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { return do_tmpfile(dir, dentry, mode, NULL); } /** * vfs_dent_type - get VFS directory entry type. * @type: UBIFS directory entry type * * This function converts UBIFS directory entry type into VFS directory entry * type. */ static unsigned int vfs_dent_type(uint8_t type) { switch (type) { case UBIFS_ITYPE_REG: return DT_REG; case UBIFS_ITYPE_DIR: return DT_DIR; case UBIFS_ITYPE_LNK: return DT_LNK; case UBIFS_ITYPE_BLK: return DT_BLK; case UBIFS_ITYPE_CHR: return DT_CHR; case UBIFS_ITYPE_FIFO: return DT_FIFO; case UBIFS_ITYPE_SOCK: return DT_SOCK; default: BUG(); } return 0; } /* * The classical Unix view for directory is that it is a linear array of * (name, inode number) entries. Linux/VFS assumes this model as well. * Particularly, 'readdir()' call wants us to return a directory entry offset * which later may be used to continue 'readdir()'ing the directory or to * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this * model because directory entries are identified by keys, which may collide. * * UBIFS uses directory entry hash value for directory offsets, so * 'seekdir()'/'telldir()' may not always work because of possible key * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work * properly by means of saving full directory entry name in the private field * of the file description object. * * This means that UBIFS cannot support NFS which requires full * 'seekdir()'/'telldir()' support. */ static int ubifs_readdir(struct file *file, struct dir_context *ctx) { int err; struct qstr nm; union ubifs_key key; struct ubifs_dent_node *dent; struct inode *dir = file_inode(file); struct ubifs_info *c = dir->i_sb->s_fs_info; dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) /* * The directory was seek'ed to a senseless position or there * are no more entries. */ return 0; if (file->f_version == 0) { /* * The file was seek'ed, which means that @file->private_data * is now invalid. This may also be just the first * 'ubifs_readdir()' invocation, in which case * @file->private_data is NULL, and the below code is * basically a no-op. */ kfree(file->private_data); file->private_data = NULL; } /* * 'generic_file_llseek()' unconditionally sets @file->f_version to * zero, and we use this for detecting whether the file was seek'ed. */ file->f_version = 1; /* File positions 0 and 1 correspond to "." and ".." */ if (ctx->pos < 2) { ubifs_assert(!file->private_data); if (!dir_emit_dots(file, ctx)) return 0; /* Find the first entry in TNC and save it */ lowest_dent_key(c, &key, dir->i_ino); nm.name = NULL; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } ctx->pos = key_hash_flash(c, &dent->key); file->private_data = dent; } dent = file->private_data; if (!dent) { /* * The directory was seek'ed to and is now readdir'ed. * Find the entry corresponding to @ctx->pos or the closest one. */ dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); nm.name = NULL; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } ctx->pos = key_hash_flash(c, &dent->key); file->private_data = dent; } while (1) { dbg_gen("feed '%s', ino %llu, new f_pos %#x", dent->name, (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); nm.len = le16_to_cpu(dent->nlen); if (!dir_emit(ctx, dent->name, nm.len, le64_to_cpu(dent->inum), vfs_dent_type(dent->type))) return 0; /* Switch to the next entry */ key_read(c, &dent->key, &key); nm.name = dent->name; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } kfree(file->private_data); ctx->pos = key_hash_flash(c, &dent->key); file->private_data = dent; cond_resched(); } out: kfree(file->private_data); file->private_data = NULL; if (err != -ENOENT) { ubifs_err(c, "cannot find next direntry, error %d", err); return err; } /* 2 is a special value indicating that there are no more direntries */ ctx->pos = 2; return 0; } /* Free saved readdir() state when the directory is closed */ static int ubifs_dir_release(struct inode *dir, struct file *file) { kfree(file->private_data); file->private_data = NULL; return 0; } /** * lock_2_inodes - a wrapper for locking two UBIFS inodes. * @inode1: first inode * @inode2: second inode * * We do not implement any tricks to guarantee strict lock ordering, because * VFS has already done it for us on the @i_mutex. So this is just a simple * wrapper function. */ static void lock_2_inodes(struct inode *inode1, struct inode *inode2) { mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); }
/* * Initialize the Linux inode and set up the operation vectors. * * When reading existing inodes from disk this is called directly from xfs_iget, * when creating a new inode it is called from xfs_ialloc after setting up the * inode. These callers have different criteria for clearing XFS_INEW, so leave * it up to the caller to deal with unlocking the inode appropriately. */ void xfs_setup_inode( struct xfs_inode *ip) { struct inode *inode = &ip->i_vnode; gfp_t gfp_mask; inode->i_ino = ip->i_ino; inode->i_state = I_NEW; inode_sb_list_add(inode); /* make the inode look hashed for the writeback code */ hlist_add_fake(&inode->i_hash); inode->i_mode = ip->i_d.di_mode; set_nlink(inode, ip->i_d.di_nlink); inode->i_uid = xfs_uid_to_kuid(ip->i_d.di_uid); inode->i_gid = xfs_gid_to_kgid(ip->i_d.di_gid); switch (inode->i_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: inode->i_rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, sysv_minor(ip->i_df.if_u2.if_rdev)); break; default: inode->i_rdev = 0; break; } inode->i_generation = ip->i_d.di_gen; i_size_write(inode, ip->i_d.di_size); inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; xfs_diflags_to_iflags(inode, ip); ip->d_ops = ip->i_mount->m_nondir_inode_ops; lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_op = &xfs_inode_operations; inode->i_fop = &xfs_file_operations; inode->i_mapping->a_ops = &xfs_address_space_operations; break; case S_IFDIR: lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) inode->i_op = &xfs_dir_ci_inode_operations; else inode->i_op = &xfs_dir_inode_operations; inode->i_fop = &xfs_dir_file_operations; ip->d_ops = ip->i_mount->m_dir_inode_ops; break; case S_IFLNK: inode->i_op = &xfs_symlink_inode_operations; if (!(ip->i_df.if_flags & XFS_IFINLINE)) inode->i_mapping->a_ops = &xfs_address_space_operations; break; default: inode->i_op = &xfs_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } /* * Ensure all page cache allocations are done from GFP_NOFS context to * prevent direct reclaim recursion back into the filesystem and blowing * stacks or deadlocking. */ gfp_mask = mapping_gfp_mask(inode->i_mapping); mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS))); /* * If there is no attribute fork no ACL can exist on this inode, * and it can't have any file capabilities attached to it either. */ if (!XFS_IFORK_Q(ip)) { inode_has_no_xattr(inode); cache_no_acl(inode); } }
static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) { struct super_block *s = i->i_sb; struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; unsigned int block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; unsigned int offset = SQUASHFS_INODE_OFFSET(inode); unsigned int ino = i->i_ino; long long next_block; unsigned int next_offset; union squashfs_inode_header_2 id, sid; struct squashfs_base_inode_header_2 *inodeb = &id.base, *sinodeb = &sid.base; TRACE("Entered squashfs_iget\n"); if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodeb, block, offset, sizeof(*sinodeb), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, sizeof(*sinodeb)); } else if (!squashfs_get_cached_block(s, (char *) inodeb, block, offset, sizeof(*inodeb), &next_block, &next_offset)) goto failed_read; squashfs_new_inode(msblk, i, inodeb, ino); switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { struct squashfs_reg_inode_header_2 *inodep = &id.reg; struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; long long frag_blk; unsigned int frag_size = 0; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; frag_blk = SQUASHFS_INVALID_BLK; if (inodep->fragment != SQUASHFS_INVALID_FRAG && !get_fragment_location_2(s, inodep->fragment, &frag_blk, &frag_size)) goto failed_read; i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; i->i_mode |= S_IFREG; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; i->i_blocks = ((i->i_size - 1) >> 9) + 1; SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; SQUASHFS_I(i)->u.s1.fragment_size = frag_size; SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->u.s1.block_list_start = next_block; SQUASHFS_I(i)->offset = next_offset; if (sblk->block_size > 4096) i->i_data.a_ops = &squashfs_aops; else i->i_data.a_ops = &squashfs_aops_4K; TRACE("File inode %x:%x, start_block %x, " "block_list_start %llx, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, next_block, next_offset); break; } case SQUASHFS_DIR_TYPE: { struct squashfs_dir_inode_header_2 *inodep = &id.dir; struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; i->i_mode |= S_IFDIR; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->offset = inodep->offset; SQUASHFS_I(i)->u.s2.directory_index_count = 0; SQUASHFS_I(i)->u.s2.parent_inode = 0; TRACE("Directory inode %x:%x, start_block %x, offset " "%x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, inodep->offset); break; } case SQUASHFS_LDIR_TYPE: { struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; i->i_mode |= S_IFDIR; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->offset = inodep->offset; SQUASHFS_I(i)->u.s2.directory_index_start = next_block; SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; SQUASHFS_I(i)->u.s2.parent_inode = 0; TRACE("Long directory inode %x:%x, start_block %x, " "offset %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, inodep->offset); break; } case SQUASHFS_SYMLINK_TYPE: { struct squashfs_symlink_inode_header_2 *inodep = &id.symlink; struct squashfs_symlink_inode_header_2 *sinodep = &sid.symlink; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->symlink_size; i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &squashfs_symlink_aops; i->i_mode |= S_IFLNK; SQUASHFS_I(i)->start_block = next_block; SQUASHFS_I(i)->offset = next_offset; TRACE("Symbolic link inode %x:%x, start_block %llx, " "offset %x\n", SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { struct squashfs_dev_inode_header_2 *inodep = &id.dev; struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: { i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; init_special_inode(i, i->i_mode, 0); break; } default: ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb->inode_type); goto failed_read1; } return 1; failed_read: ERROR("Unable to read inode [%x:%x]\n", block, offset); failed_read1: return 0; }
/* * Initialize the Linux inode, set up the operation vectors and * unlock the inode. * * When reading existing inodes from disk this is called directly * from xfs_iget, when creating a new inode it is called from * xfs_ialloc after setting up the inode. * * We are always called with an uninitialised linux inode here. * We need to initialise the necessary fields and take a reference * on it. */ void xfs_setup_inode( struct xfs_inode *ip) { struct inode *inode = &ip->i_vnode; inode->i_ino = ip->i_ino; inode->i_state = I_NEW; inode_sb_list_add(inode); /* make the inode look hashed for the writeback code */ hlist_add_fake(&inode->i_hash); inode->i_mode = ip->i_d.di_mode; set_nlink(inode, ip->i_d.di_nlink); inode->i_uid = ip->i_d.di_uid; inode->i_gid = ip->i_d.di_gid; switch (inode->i_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: inode->i_rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, sysv_minor(ip->i_df.if_u2.if_rdev)); break; default: inode->i_rdev = 0; break; } inode->i_generation = ip->i_d.di_gen; i_size_write(inode, ip->i_d.di_size); inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; xfs_diflags_to_iflags(inode, ip); switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_op = &xfs_inode_operations; inode->i_fop = &xfs_file_operations; inode->i_mapping->a_ops = &xfs_address_space_operations; break; case S_IFDIR: if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) inode->i_op = &xfs_dir_ci_inode_operations; else inode->i_op = &xfs_dir_inode_operations; inode->i_fop = &xfs_dir_file_operations; break; case S_IFLNK: inode->i_op = &xfs_symlink_inode_operations; if (!(ip->i_df.if_flags & XFS_IFINLINE)) inode->i_mapping->a_ops = &xfs_address_space_operations; break; default: inode->i_op = &xfs_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } /* * If there is no attribute fork no ACL can exist on this inode, * and it can't have any file capabilities attached to it either. */ if (!XFS_IFORK_Q(ip)) { inode_has_no_xattr(inode); cache_no_acl(inode); } xfs_iflags_clear(ip, XFS_INEW); barrier(); unlock_new_inode(inode); }
static struct inode *sdcardfskk_iget(struct super_block *sb, struct inode *lower_inode) { struct sdcardfskk_inode_info *info; struct inode *inode; /* the new inode to return */ int err; inode = iget5_locked(sb, /* our superblock */ /* * hashval: we use inode number, but we can * also use "(unsigned long)lower_inode" * instead. */ lower_inode->i_ino, /* hashval */ sdcardfskk_inode_test, /* inode comparison function */ sdcardfskk_inode_set, /* inode init function */ lower_inode); /* data passed to test+set fxns */ if (!inode) { err = -EACCES; iput(lower_inode); return ERR_PTR(err); } /* if found a cached inode, then just return it */ if (!(inode->i_state & I_NEW)) return inode; /* initialize new inode */ info = SDCARDFSKK_I(inode); inode->i_ino = lower_inode->i_ino; if (!igrab(lower_inode)) { err = -ESTALE; return ERR_PTR(err); } sdcardfskk_set_lower_inode(inode, lower_inode); inode->i_version++; /* use different set of inode ops for symlinks & directories */ if (S_ISDIR(lower_inode->i_mode)) inode->i_op = &sdcardfskk_dir_iops; else if (S_ISLNK(lower_inode->i_mode)) inode->i_op = &sdcardfskk_symlink_iops; else inode->i_op = &sdcardfskk_main_iops; /* use different set of file ops for directories */ if (S_ISDIR(lower_inode->i_mode)) inode->i_fop = &sdcardfskk_dir_fops; else inode->i_fop = &sdcardfskk_main_fops; inode->i_mapping->a_ops = &sdcardfskk_aops; inode->i_atime.tv_sec = 0; inode->i_atime.tv_nsec = 0; inode->i_mtime.tv_sec = 0; inode->i_mtime.tv_nsec = 0; inode->i_ctime.tv_sec = 0; inode->i_ctime.tv_nsec = 0; /* properly initialize special inodes */ if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); /* all well, copy inode attributes, don't need to hold i_mutex here */ sdcardfskk_copy_inode_attr(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); fix_derived_permission(inode); unlock_new_inode(inode); return inode; }
void hpfs_read_inode(struct inode *i) { struct buffer_head *bh; struct fnode *fnode; struct super_block *sb = i->i_sb; struct hpfs_inode_info *hpfs_inode = hpfs_i(i); void *ea; int ea_size; if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) { /* */ make_bad_inode(i); return; } if (hpfs_sb(i->i_sb)->sb_eas) { if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) { if (ea_size == 2) { i->i_uid = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_uid = 1; } kfree(ea); } if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) { if (ea_size == 2) { i->i_gid = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_gid = 1; } kfree(ea); } if ((ea = hpfs_get_ea(i->i_sb, fnode, "SYMLINK", &ea_size))) { kfree(ea); i->i_mode = S_IFLNK | 0777; i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &hpfs_symlink_aops; set_nlink(i, 1); i->i_size = ea_size; i->i_blocks = 1; brelse(bh); return; } if ((ea = hpfs_get_ea(i->i_sb, fnode, "MODE", &ea_size))) { int rdev = 0; umode_t mode = hpfs_sb(sb)->sb_mode; if (ea_size == 2) { mode = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_mode = 1; } kfree(ea); i->i_mode = mode; if (S_ISBLK(mode) || S_ISCHR(mode)) { if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) { if (ea_size == 4) rdev = le32_to_cpu(*(__le32*)ea); kfree(ea); } } if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { brelse(bh); set_nlink(i, 1); i->i_size = 0; i->i_blocks = 1; init_special_inode(i, mode, new_decode_dev(rdev)); return; } } } if (fnode->dirflag) { int n_dnodes, n_subdirs; i->i_mode |= S_IFDIR; i->i_op = &hpfs_dir_iops; i->i_fop = &hpfs_dir_ops; hpfs_inode->i_parent_dir = le32_to_cpu(fnode->up); hpfs_inode->i_dno = le32_to_cpu(fnode->u.external[0].disk_secno); if (hpfs_sb(sb)->sb_chk >= 2) { struct buffer_head *bh0; if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0); } n_dnodes = 0; n_subdirs = 0; hpfs_count_dnodes(i->i_sb, hpfs_inode->i_dno, &n_dnodes, &n_subdirs, NULL); i->i_blocks = 4 * n_dnodes; i->i_size = 2048 * n_dnodes; set_nlink(i, 2 + n_subdirs); } else { i->i_mode |= S_IFREG; if (!hpfs_inode->i_ea_mode) i->i_mode &= ~0111; i->i_op = &hpfs_file_iops; i->i_fop = &hpfs_file_ops; set_nlink(i, 1); i->i_size = le32_to_cpu(fnode->file_size); i->i_blocks = ((i->i_size + 511) >> 9) + 1; i->i_data.a_ops = &hpfs_aops; hpfs_i(i)->mmu_private = i->i_size; } brelse(bh); }
struct inode *f2fs_iget_nowait(struct super_block *sb, unsigned long ino) { struct f2fs_iget_args args = { .ino = ino, .on_free = 0 }; struct inode *inode = ilookup5(sb, ino, f2fs_iget_test, &args); if (inode) return inode; if (!args.on_free) return f2fs_iget(sb, ino); return ERR_PTR(-ENOENT); } static int do_read_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); struct page *node_page; struct f2fs_node *rn; struct f2fs_inode *ri; /* Check if ino is within scope */ check_nid_range(sbi, inode->i_ino); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) return PTR_ERR(node_page); rn = page_address(node_page); ri = &(rn->i); inode->i_mode = le16_to_cpu(ri->i_mode); i_uid_write(inode, le32_to_cpu(ri->i_uid)); i_gid_write(inode, le32_to_cpu(ri->i_gid)); set_nlink(inode, le32_to_cpu(ri->i_links)); inode->i_size = le64_to_cpu(ri->i_size); inode->i_blocks = le64_to_cpu(ri->i_blocks); inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime); inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime); inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime); inode->i_atime.tv_nsec = le32_to_cpu(ri->i_atime_nsec); inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); inode->i_generation = le32_to_cpu(ri->i_generation); fi->i_current_depth = le32_to_cpu(ri->i_current_depth); fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); fi->i_flags = le32_to_cpu(ri->i_flags); fi->flags = 0; fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1; fi->i_advise = ri->i_advise; fi->i_pino = le32_to_cpu(ri->i_pino); get_extent_info(&fi->ext, ri->i_ext); f2fs_put_page(node_page, 1); return 0; } struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) { struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; int ret; inode = iget_locked(sb, ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) goto make_now; ret = do_read_inode(inode); if (ret) goto bad_inode; if (!sbi->por_doing && inode->i_nlink == 0) { ret = -ENOENT; goto bad_inode; } make_now: if (ino == F2FS_NODE_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_node_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); } else if (ino == F2FS_META_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_meta_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); } else if (S_ISREG(inode->i_mode)) { inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | __GFP_ZERO); } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { inode->i_op = &f2fs_special_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); } else { ret = -EIO; goto bad_inode; } unlock_new_inode(inode); return inode; bad_inode: iget_failed(inode); return ERR_PTR(ret); } void update_inode(struct inode *inode, struct page *node_page) { struct f2fs_node *rn; struct f2fs_inode *ri; wait_on_page_writeback(node_page); rn = page_address(node_page); ri = &(rn->i); ri->i_mode = cpu_to_le16(inode->i_mode); ri->i_advise = F2FS_I(inode)->i_advise; ri->i_uid = cpu_to_le32(i_uid_read(inode)); ri->i_gid = cpu_to_le32(i_gid_read(inode)); ri->i_links = cpu_to_le32(inode->i_nlink); ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_blocks = cpu_to_le64(inode->i_blocks); set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec); ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth); ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); ri->i_generation = cpu_to_le32(inode->i_generation); set_cold_node(inode, node_page); set_page_dirty(node_page); } int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct page *node_page; bool need_lock = false; if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) return 0; if (wbc) f2fs_balance_fs(sbi); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) return PTR_ERR(node_page); if (!PageDirty(node_page)) { need_lock = true; f2fs_put_page(node_page, 1); mutex_lock(&sbi->write_inode); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { mutex_unlock(&sbi->write_inode); return PTR_ERR(node_page); } } update_inode(inode, node_page); f2fs_put_page(node_page, 1); if (need_lock) mutex_unlock(&sbi->write_inode); return 0; } /* * Called at the last iput() if i_nlink is zero */ void f2fs_evict_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); truncate_inode_pages(&inode->i_data, 0); if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) goto no_delete; BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents)); remove_dirty_dir_inode(inode); if (inode->i_nlink || is_bad_inode(inode)) goto no_delete; set_inode_flag(F2FS_I(inode), FI_NO_ALLOC); i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) f2fs_truncate(inode); remove_inode_page(inode); no_delete: clear_inode(inode); }
static void fill_in_inode(struct inode *tmp_inode, FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; /* Linux can not store file creation time unfortunately so ignore it */ tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ /* BB fill in uid and gid here? with help from winbind? or retrieve from NTFS stream extended attribute */ if (atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_uid = cifs_sb->mnt_uid; tmp_inode->i_gid = cifs_sb->mnt_gid; /* set default mode. will override for dirs below */ tmp_inode->i_mode = cifs_sb->mnt_file_mode; } if (attr & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ if(atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_mode = cifs_sb->mnt_dir_mode; } tmp_inode->i_mode |= S_IFDIR; /* we no longer mark these because we could not follow them */ /* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; */ } else { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; if (attr & ATTR_READONLY) tmp_inode->i_mode &= ~(S_IWUGO); } /* could add code here - to validate if device or weird share type? */ /* can not fill in nlink here as in qpathinfo version and Unx search */ if (atomic_read(&cifsInfo->inUse) == 0) { atomic_set(&cifsInfo->inUse, 1); } if (is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ i_size_write(tmp_inode, end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, even though the reported blocksize is larger */ tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; } if (allocation_size < end_of_file) cFYI(1, ("May be sparse file, allocation less than file size")); cFYI(1, ("File Size %ld and blocks %ld and blocksize %ld", (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, tmp_inode->i_blksize)); if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) tmp_inode->i_fop = &cifs_file_direct_ops; else tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; if(isNewInode) return; /* No sense invalidating pages for new inode since we have not started caching readahead file data yet */ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && (local_size == tmp_inode->i_size)) { cFYI(1, ("inode exists but unchanged")); } else { /* file may have changed on server */ cFYI(1, ("invalidate inode, readdir detected change")); invalidate_remote_inode(tmp_inode); } } else if (S_ISDIR(tmp_inode->i_mode)) { cFYI(1, ("Directory inode")); tmp_inode->i_op = &cifs_dir_inode_ops; tmp_inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(tmp_inode->i_mode)) { cFYI(1, ("Symbolic Link inode")); tmp_inode->i_op = &cifs_symlink_inode_ops; } else { cFYI(1, ("Init special inode")); init_special_inode(tmp_inode, tmp_inode->i_mode, tmp_inode->i_rdev); } }
int v9fs_init_inode(struct v9fs_session_info *v9ses, struct inode *inode, int mode, dev_t rdev) { int err = 0; inode_init_owner(inode, NULL, mode); inode->i_blocks = 0; inode->i_rdev = rdev; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mapping->a_ops = &v9fs_addr_operations; switch (mode & S_IFMT) { case S_IFIFO: case S_IFBLK: case S_IFCHR: case S_IFSOCK: if (v9fs_proto_dotl(v9ses)) { inode->i_op = &v9fs_file_inode_operations_dotl; inode->i_fop = &v9fs_file_operations_dotl; } else if (v9fs_proto_dotu(v9ses)) { inode->i_op = &v9fs_file_inode_operations; inode->i_fop = &v9fs_file_operations; } else { P9_DPRINTK(P9_DEBUG_ERROR, "special files without extended mode\n"); err = -EINVAL; goto error; } init_special_inode(inode, inode->i_mode, inode->i_rdev); break; case S_IFREG: if (v9fs_proto_dotl(v9ses)) { inode->i_op = &v9fs_file_inode_operations_dotl; if (v9ses->cache) inode->i_fop = &v9fs_cached_file_operations_dotl; else inode->i_fop = &v9fs_file_operations_dotl; } else { inode->i_op = &v9fs_file_inode_operations; if (v9ses->cache) inode->i_fop = &v9fs_cached_file_operations; else inode->i_fop = &v9fs_file_operations; } break; case S_IFLNK: if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) { P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with " "legacy protocol.\n"); err = -EINVAL; goto error; } if (v9fs_proto_dotl(v9ses)) inode->i_op = &v9fs_symlink_inode_operations_dotl; else inode->i_op = &v9fs_symlink_inode_operations; break; case S_IFDIR: inc_nlink(inode); if (v9fs_proto_dotl(v9ses)) inode->i_op = &v9fs_dir_inode_operations_dotl; else if (v9fs_proto_dotu(v9ses)) inode->i_op = &v9fs_dir_inode_operations_dotu; else inode->i_op = &v9fs_dir_inode_operations; if (v9fs_proto_dotl(v9ses)) inode->i_fop = &v9fs_dir_operations_dotl; else inode->i_fop = &v9fs_dir_operations; break; default: P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", mode, mode & S_IFMT); err = -EINVAL; goto error; } error: return err; }
static void unix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 type = le32_to_cpu(pfindData->Type); __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->time = jiffies; atomic_inc(&cifsInfo->inUse); /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; } else if (type == UNIX_DIR) { *pobject_type = DT_DIR; tmp_inode->i_mode |= S_IFDIR; } else if (type == UNIX_CHARDEV) { *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_BLOCKDEV) { *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_FIFO) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); if (is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ i_size_write(tmp_inode,end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, not the real blocksize */ tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; } if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) tmp_inode->i_fop = &cifs_file_direct_ops; else tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; if(isNewInode) return; /* No sense invalidating pages for new inode since we have not started caching readahead file data yet */ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && (local_size == tmp_inode->i_size)) { cFYI(1, ("inode exists but unchanged")); } else { /* file may have changed on server */ cFYI(1, ("invalidate inode, readdir detected change")); invalidate_remote_inode(tmp_inode); } } else if (S_ISDIR(tmp_inode->i_mode)) { cFYI(1, ("Directory inode")); tmp_inode->i_op = &cifs_dir_inode_ops; tmp_inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(tmp_inode->i_mode)) { cFYI(1, ("Symbolic Link inode")); tmp_inode->i_op = &cifs_symlink_inode_ops; /* tmp_inode->i_fop = *//* do not need to set to anything */ } else { cFYI(1, ("Special inode")); init_special_inode(tmp_inode, tmp_inode->i_mode, tmp_inode->i_rdev); } }
/* * NAME: jfs_mknod * * FUNCTION: Create a special file (device) */ static int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct jfs_inode_info *jfs_ip; struct btstack btstack; struct component_name dname; ino_t ino; struct inode *ip; struct inode *iplist[2]; int rc; tid_t tid; struct tblock *tblk; if (!new_valid_dev(rdev)) return -EINVAL; jfs_info("jfs_mknod: %s", dentry->d_name.name); dquot_initialize(dir); if ((rc = get_UCSname(&dname, dentry))) goto out; ip = ialloc(dir, mode); if (IS_ERR(ip)) { rc = PTR_ERR(ip); goto out1; } jfs_ip = JFS_IP(ip); tid = txBegin(dir->i_sb, 0); mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT); mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); rc = jfs_init_acl(tid, ip, dir); if (rc) goto out3; rc = jfs_init_security(tid, ip, dir, &dentry->d_name); if (rc) { txAbort(tid, 0); goto out3; } if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) { txAbort(tid, 0); goto out3; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; ino = ip->i_ino; if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) { txAbort(tid, 0); goto out3; } ip->i_op = &jfs_file_inode_operations; jfs_ip->dev = new_encode_dev(rdev); init_special_inode(ip, ip->i_mode, rdev); mark_inode_dirty(ip); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); iplist[0] = dir; iplist[1] = ip; rc = txCommit(tid, 2, iplist, 0); out3: txEnd(tid); mutex_unlock(&JFS_IP(ip)->commit_mutex); mutex_unlock(&JFS_IP(dir)->commit_mutex); if (rc) { free_ea_wmap(ip); clear_nlink(ip); unlock_new_inode(ip); iput(ip); } else { d_instantiate(dentry, ip); unlock_new_inode(ip); } out1: free_UCSname(&dname); out: jfs_info("jfs_mknod: returning %d", rc); return rc; }
int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, int create_ino) { struct super_block *sb; struct ocfs2_super *osb; int status = -EINVAL; mlog_entry("(0x%p, size:%llu)\n", inode, (unsigned long long)le64_to_cpu(fe->i_size)); sb = inode->i_sb; osb = OCFS2_SB(sb); /* this means that read_inode cannot create a superblock inode * today. change if needed. */ if (!OCFS2_IS_VALID_DINODE(fe) || !(fe->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { mlog(0, "Invalid dinode: i_ino=%lu, i_blkno=%llu, " "signature = %.*s, flags = 0x%x\n", inode->i_ino, (unsigned long long)le64_to_cpu(fe->i_blkno), 7, fe->i_signature, le32_to_cpu(fe->i_flags)); goto bail; } if (le32_to_cpu(fe->i_fs_generation) != osb->fs_generation) { mlog(ML_ERROR, "file entry generation does not match " "superblock! osb->fs_generation=%x, " "fe->i_fs_generation=%x\n", osb->fs_generation, le32_to_cpu(fe->i_fs_generation)); goto bail; } OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); inode->i_version = 1; inode->i_generation = le32_to_cpu(fe->i_generation); inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); inode->i_mode = le16_to_cpu(fe->i_mode); inode->i_uid = le32_to_cpu(fe->i_uid); inode->i_gid = le32_to_cpu(fe->i_gid); /* Fast symlinks will have i_size but no allocated clusters. */ if (S_ISLNK(inode->i_mode) && !fe->i_clusters) inode->i_blocks = 0; else inode->i_blocks = ocfs2_inode_sector_count(inode); inode->i_mapping->a_ops = &ocfs2_aops; inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime); inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec); inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime); inode->i_mtime.tv_nsec = le32_to_cpu(fe->i_mtime_nsec); inode->i_ctime.tv_sec = le64_to_cpu(fe->i_ctime); inode->i_ctime.tv_nsec = le32_to_cpu(fe->i_ctime_nsec); if (OCFS2_I(inode)->ip_blkno != le64_to_cpu(fe->i_blkno)) mlog(ML_ERROR, "ip_blkno %llu != i_blkno %llu!\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)le64_to_cpu(fe->i_blkno)); inode->i_nlink = le16_to_cpu(fe->i_links_count); if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE; if (fe->i_flags & cpu_to_le32(OCFS2_LOCAL_ALLOC_FL)) { OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; mlog(0, "local alloc inode: i_ino=%lu\n", inode->i_ino); } else if (fe->i_flags & cpu_to_le32(OCFS2_BITMAP_FL)) { OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; } else if (fe->i_flags & cpu_to_le32(OCFS2_SUPER_BLOCK_FL)) { mlog(0, "superblock inode: i_ino=%lu\n", inode->i_ino); /* we can't actually hit this as read_inode can't * handle superblocks today ;-) */ BUG(); } switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_fop = &ocfs2_fops; inode->i_op = &ocfs2_file_iops; i_size_write(inode, le64_to_cpu(fe->i_size)); break; case S_IFDIR: inode->i_op = &ocfs2_dir_iops; inode->i_fop = &ocfs2_dops; i_size_write(inode, le64_to_cpu(fe->i_size)); break; case S_IFLNK: if (ocfs2_inode_is_fast_symlink(inode)) inode->i_op = &ocfs2_fast_symlink_inode_operations; else inode->i_op = &ocfs2_symlink_inode_operations; i_size_write(inode, le64_to_cpu(fe->i_size)); break; default: inode->i_op = &ocfs2_special_file_iops; init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } if (create_ino) { inode->i_ino = ino_from_blkno(inode->i_sb, le64_to_cpu(fe->i_blkno)); /* * If we ever want to create system files from kernel, * the generation argument to * ocfs2_inode_lock_res_init() will have to change. */ BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres, OCFS2_LOCK_TYPE_META, 0, inode); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres, OCFS2_LOCK_TYPE_OPEN, 0, inode); } ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres, OCFS2_LOCK_TYPE_RW, inode->i_generation, inode); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres, OCFS2_LOCK_TYPE_DATA, inode->i_generation, inode); ocfs2_set_inode_flags(inode); status = 0; bail: mlog_exit(status); return status; }
static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = old_dentry->d_inode; struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, .dirtied_ino_d = ALIGN(ui->data_len, 8) }; /* * Budget request settings: new direntry, changing the target inode, * changing the parent inode. */ dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, inode->i_nlink, dir->i_ino); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = dbg_check_synced_i_size(c, inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) return err; lock_2_inodes(dir, inode); inc_nlink(inode); ihold(inode); inode->i_ctime = ubifs_current_time(inode); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode); return err; } static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = dentry->d_inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; unsigned int saved_nlink = inode->i_nlink; /* * Budget request settings: deletion direntry, deletion inode (+1 for * @dirtied_ino), changing the parent directory inode. If budgeting * fails, go ahead anyway because we have extra space reserved for * deletions. */ dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, inode->i_nlink, dir->i_ino); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = dbg_check_synced_i_size(c, inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); drop_nlink(inode); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; set_nlink(inode, saved_nlink); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } /** * check_dir_empty - check if a directory is empty or not. * @c: UBIFS file-system description object * @dir: VFS inode object of the directory to check * * This function checks if directory @dir is empty. Returns zero if the * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes * in case of of errors. */ static int check_dir_empty(struct ubifs_info *c, struct inode *dir) { struct qstr nm = { .name = NULL }; struct ubifs_dent_node *dent; union ubifs_key key; int err; lowest_dent_key(c, &key, dir->i_ino); dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -ENOENT) err = 0; } else { kfree(dent); err = -ENOTEMPTY; } return err; } static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = dentry->d_inode; int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; /* * Budget request settings: deletion direntry, deletion inode and * changing the parent inode. If budgeting fails, go ahead anyway * because we have extra space reserved for deletions. */ dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, dir->i_ino); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = check_dir_empty(c, dentry->d_inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); clear_nlink(inode); drop_nlink(dir); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(dir); set_nlink(inode, 2); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s', mode %#hx in dir ino %lu", dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); inc_nlink(dir); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) { ubifs_err("cannot create directory, error %d", err); goto out_cancel; } mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(dir); mutex_unlock(&dir_ui->ui_mutex); make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; union ubifs_dev_desc *dev = NULL; int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, devlen = 0; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(devlen, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s' in dir ino %lu", dentry->d_name.len, dentry->d_name.name, dir->i_ino); if (!new_valid_dev(rdev)) return -EINVAL; if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) return -ENOMEM; devlen = ubifs_encode_dev(dev, rdev); } err = ubifs_budget_space(c, &req); if (err) { kfree(dev); return err; } inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { kfree(dev); err = PTR_ERR(inode); goto out_budg; } init_special_inode(inode, inode->i_mode, rdev); inode->i_size = ubifs_inode(inode)->ui_size = devlen; ui = ubifs_inode(inode); ui->data = dev; ui->data_len = devlen; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len, dentry->d_name.name, symname, dir->i_ino); if (len > UBIFS_MAX_INO_DATA) return -ENAMETOOLONG; err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } ui = ubifs_inode(inode); ui->data = kmalloc(len + 1, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_inode; } memcpy(ui->data, symname, len); ((char *)ui->data)[len] = '\0'; /* * The terminating zero byte is not written to the flash media and it * is put just to make later in-memory string processing simpler. Thus, * data length is @len, not @len + %1. */ ui->data_len = len; inode->i_size = ubifs_inode(inode)->ui_size = len; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } /** * lock_3_inodes - a wrapper for locking three UBIFS inodes. * @inode1: first inode * @inode2: second inode * @inode3: third inode * * This function is used for 'ubifs_rename()' and @inode1 may be the same as * @inode2 whereas @inode3 may be %NULL. * * We do not implement any tricks to guarantee strict lock ordering, because * VFS has already done it for us on the @i_mutex. So this is just a simple * wrapper function. */ static void lock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); if (inode2 != inode1) mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); if (inode3) mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3); } /** * unlock_3_inodes - a wrapper for unlocking three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode */ static void unlock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { if (inode3) mutex_unlock(&ubifs_inode(inode3)->ui_mutex); if (inode1 != inode2) mutex_unlock(&ubifs_inode(inode2)->ui_mutex); mutex_unlock(&ubifs_inode(inode1)->ui_mutex); } static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); int unlink = !!new_inode; int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len); int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 3 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; unsigned int saved_nlink = 0; /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. * * However, this operation also marks the target inode as dirty and * does not write it, so we allocate budget for the target inode * separately. */ dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in " "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len, new_dentry->d_name.name, new_dir->i_ino); ubifs_assert(mutex_is_locked(&old_dir->i_mutex)); ubifs_assert(mutex_is_locked(&new_dir->i_mutex)); if (unlink) ubifs_assert(mutex_is_locked(&new_inode->i_mutex)); if (unlink && is_dir) { err = check_dir_empty(c, new_inode); if (err) return err; } err = ubifs_budget_space(c, &req); if (err) return err; err = ubifs_budget_space(c, &ino_req); if (err) { ubifs_release_budget(c, &req); return err; } lock_3_inodes(old_dir, new_dir, new_inode); /* * Like most other Unix systems, set the @i_ctime for inodes on a * rename. */ time = ubifs_current_time(old_dir); old_inode->i_ctime = time; /* We must adjust parent link count when renaming directories */ if (is_dir) { if (move) { /* * @old_dir loses a link because we are moving * @old_inode to a different directory. */ drop_nlink(old_dir); /* * @new_dir only gains a link if we are not also * overwriting an existing directory. */ if (!unlink) inc_nlink(new_dir); } else { /* * @old_inode is not moving to a different directory, * but @old_dir still loses a link if we are * overwriting an existing directory. */ if (unlink) drop_nlink(old_dir); } } old_dir->i_size -= old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; /* * And finally, if we unlinked a direntry which happened to have the * same name as the moved direntry, we have to decrement @i_nlink of * the unlinked inode and change its ctime. */ if (unlink) { /* * Directories cannot have hard-links, so if this is a * directory, just clear @i_nlink. */ saved_nlink = new_inode->i_nlink; if (is_dir) clear_nlink(new_inode); else drop_nlink(new_inode); new_inode->i_ctime = time; } else { new_dir->i_size += new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } /* * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode * is dirty, because this will be done later on at the end of * 'ubifs_rename()'. */ if (IS_SYNC(old_inode)) { sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); if (unlink && IS_SYNC(new_inode)) sync = 1; } err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, sync); if (err) goto out_cancel; unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &req); mutex_lock(&old_inode_ui->ui_mutex); release = old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); mutex_unlock(&old_inode_ui->ui_mutex); if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) err = old_inode->i_sb->s_op->write_inode(old_inode, NULL); return err; out_cancel: if (unlink) { set_nlink(new_inode, saved_nlink); } else { new_dir->i_size -= new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } old_dir->i_size += old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; if (is_dir) { if (move) { inc_nlink(old_dir); if (!unlink) drop_nlink(new_dir); } else { if (unlink) inc_nlink(old_dir); } } unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); return err; } int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { loff_t size; struct inode *inode = dentry->d_inode; struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); stat->dev = inode->i_sb->s_dev; stat->ino = inode->i_ino; stat->mode = inode->i_mode; stat->nlink = inode->i_nlink; stat->uid = inode->i_uid; stat->gid = inode->i_gid; stat->rdev = inode->i_rdev; stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; stat->blksize = UBIFS_BLOCK_SIZE; stat->size = ui->ui_size; /* * Unfortunately, the 'stat()' system call was designed for block * device based file systems, and it is not appropriate for UBIFS, * because UBIFS does not have notion of "block". For example, it is * difficult to tell how many block a directory takes - it actually * takes less than 300 bytes, but we have to round it to block size, * which introduces large mistake. This makes utilities like 'du' to * report completely senseless numbers. This is the reason why UBIFS * goes the same way as JFFS2 - it reports zero blocks for everything * but regular files, which makes more sense than reporting completely * wrong sizes. */ if (S_ISREG(inode->i_mode)) { size = ui->xattr_size; size += stat->size; size = ALIGN(size, UBIFS_BLOCK_SIZE); /* * Note, user-space expects 512-byte blocks count irrespectively * of what was reported in @stat->size. */ stat->blocks = size >> 9; } else stat->blocks = 0; mutex_unlock(&ui->ui_mutex); return 0; } const struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, .create = ubifs_create, .link = ubifs_link, .symlink = ubifs_symlink, .unlink = ubifs_unlink, .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, #ifdef CONFIG_UBIFS_FS_XATTR .setxattr = ubifs_setxattr, .getxattr = ubifs_getxattr, .listxattr = ubifs_listxattr, .removexattr = ubifs_removexattr, #endif }; const struct file_operations ubifs_dir_operations = { .llseek = ubifs_dir_llseek, .release = ubifs_dir_release, .read = generic_read_dir, .readdir = ubifs_readdir, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif };
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, };
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; unsigned short dev; int devlen = 0; __u32 alloclen, phys_ofs; __u32 writtenlen; int ret; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev)); devlen = sizeof(dev); } /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_file_inode_operations; init_special_inode(inode, inode->i_mode, rdev); f = JFFS2_INODE_INFO(inode); ri->dsize = ri->csize = devlen; ri->totlen = sizeof(*ri) + ri->csize; ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = crc32(0, &dev, devlen); ri->node_crc = crc32(0, ri, sizeof(*ri)-8); fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); /* Work out where to put the dirent node now. */ writtenlen = (writtenlen+3)&~3; phys_ofs += writtenlen; alloclen -= writtenlen; if (alloclen < sizeof(*rd)+namelen) { /* Not enough space left in this chunk. Get some more */ jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; /* XXX: This is ugly. */ rd->type = (mode & S_IFMT) >> 12; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } dir_i->i_mtime = dir_i->i_ctime = rd->mctime; jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); d_instantiate(dentry, inode); return 0; }
/* * Initialise VFS inode by reading inode from inode table (compressed * metadata). The format and amount of data read depends on type. */ int squashfs_read_inode(struct inode *inode, long long ino) { struct super_block *sb = inode->i_sb; struct squashfs_sb_info *msblk = sb->s_fs_info; u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table; int err, type, offset = SQUASHFS_INODE_OFFSET(ino); union squashfs_inode squashfs_ino; struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; int xattr_id = SQUASHFS_INVALID_XATTR; TRACE("Entered squashfs_read_inode\n"); /* * Read inode base common to all inode types. */ err = squashfs_read_metadata(sb, sqshb_ino, &block, &offset, sizeof(*sqshb_ino)); if (err < 0) goto failed_read; err = squashfs_new_inode(sb, inode, sqshb_ino); if (err) goto failed_read; block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table; offset = SQUASHFS_INODE_OFFSET(ino); type = le16_to_cpu(sqshb_ino->inode_type); switch (type) { case SQUASHFS_REG_TYPE: { unsigned int frag_offset, frag; int frag_size; u64 frag_blk; struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; frag = le32_to_cpu(sqsh_ino->fragment); if (frag != SQUASHFS_INVALID_FRAG) { frag_offset = le32_to_cpu(sqsh_ino->offset); frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); if (frag_size < 0) { err = frag_size; goto failed_read; } } else { frag_blk = SQUASHFS_INVALID_BLK; frag_size = 0; frag_offset = 0; } set_nlink(inode, 1); inode->i_size = le32_to_cpu(sqsh_ino->file_size); inode->i_fop = &generic_ro_fops; inode->i_mode |= S_IFREG; inode->i_blocks = ((inode->i_size - 1) >> 9) + 1; squashfs_i(inode)->fragment_block = frag_blk; squashfs_i(inode)->fragment_size = frag_size; squashfs_i(inode)->fragment_offset = frag_offset; squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); squashfs_i(inode)->block_list_start = block; squashfs_i(inode)->offset = offset; inode->i_data.a_ops = &squashfs_aops; TRACE("File inode %x:%x, start_block %llx, block_list_start " "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino), offset, squashfs_i(inode)->start, block, offset); break; } case SQUASHFS_LREG_TYPE: { unsigned int frag_offset, frag; int frag_size; u64 frag_blk; struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; frag = le32_to_cpu(sqsh_ino->fragment); if (frag != SQUASHFS_INVALID_FRAG) { frag_offset = le32_to_cpu(sqsh_ino->offset); frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); if (frag_size < 0) { err = frag_size; goto failed_read; } } else { frag_blk = SQUASHFS_INVALID_BLK; frag_size = 0; frag_offset = 0; } xattr_id = le32_to_cpu(sqsh_ino->xattr); set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); inode->i_size = le64_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_inode_ops; inode->i_fop = &generic_ro_fops; inode->i_mode |= S_IFREG; inode->i_blocks = (inode->i_size - le64_to_cpu(sqsh_ino->sparse) + 511) >> 9; squashfs_i(inode)->fragment_block = frag_blk; squashfs_i(inode)->fragment_size = frag_size; squashfs_i(inode)->fragment_offset = frag_offset; squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block); squashfs_i(inode)->block_list_start = block; squashfs_i(inode)->offset = offset; inode->i_data.a_ops = &squashfs_aops; TRACE("File inode %x:%x, start_block %llx, block_list_start " "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino), offset, squashfs_i(inode)->start, block, offset); break; } case SQUASHFS_DIR_TYPE: { struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); inode->i_size = le16_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_dir_inode_ops; inode->i_fop = &squashfs_dir_ops; inode->i_mode |= S_IFDIR; squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset); squashfs_i(inode)->dir_idx_cnt = 0; squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode); TRACE("Directory inode %x:%x, start_block %llx, offset %x\n", SQUASHFS_INODE_BLK(ino), offset, squashfs_i(inode)->start, le16_to_cpu(sqsh_ino->offset)); break; } case SQUASHFS_LDIR_TYPE: { struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; xattr_id = le32_to_cpu(sqsh_ino->xattr); set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); inode->i_size = le32_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_dir_inode_ops; inode->i_fop = &squashfs_dir_ops; inode->i_mode |= S_IFDIR; squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset); squashfs_i(inode)->dir_idx_start = block; squashfs_i(inode)->dir_idx_offset = offset; squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count); squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode); TRACE("Long directory inode %x:%x, start_block %llx, offset " "%x\n", SQUASHFS_INODE_BLK(ino), offset, squashfs_i(inode)->start, le16_to_cpu(sqsh_ino->offset)); break; } case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE: { struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); inode->i_op = &squashfs_symlink_inode_ops; inode->i_data.a_ops = &squashfs_symlink_aops; inode->i_mode |= S_IFLNK; squashfs_i(inode)->start = block; squashfs_i(inode)->offset = offset; if (type == SQUASHFS_LSYMLINK_TYPE) { __le32 xattr; err = squashfs_read_metadata(sb, NULL, &block, &offset, inode->i_size); if (err < 0) goto failed_read; err = squashfs_read_metadata(sb, &xattr, &block, &offset, sizeof(xattr)); if (err < 0) goto failed_read; xattr_id = le32_to_cpu(xattr); } TRACE("Symbolic link inode %x:%x, start_block %llx, offset " "%x\n", SQUASHFS_INODE_BLK(ino), offset, block, offset); break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; unsigned int rdev; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; if (type == SQUASHFS_CHRDEV_TYPE) inode->i_mode |= S_IFCHR; else inode->i_mode |= S_IFBLK; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); rdev = le32_to_cpu(sqsh_ino->rdev); init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(ino), offset, rdev); break; } case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE: { struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev; unsigned int rdev; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; if (type == SQUASHFS_LCHRDEV_TYPE) inode->i_mode |= S_IFCHR; else inode->i_mode |= S_IFBLK; xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_op = &squashfs_inode_ops; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); rdev = le32_to_cpu(sqsh_ino->rdev); init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(ino), offset, rdev); break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: { struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; if (type == SQUASHFS_FIFO_TYPE) inode->i_mode |= S_IFIFO; else inode->i_mode |= S_IFSOCK; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); init_special_inode(inode, inode->i_mode, 0); break; } case SQUASHFS_LFIFO_TYPE: case SQUASHFS_LSOCKET_TYPE: { struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; if (type == SQUASHFS_LFIFO_TYPE) inode->i_mode |= S_IFIFO; else inode->i_mode |= S_IFSOCK; xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_op = &squashfs_inode_ops; set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); init_special_inode(inode, inode->i_mode, 0); break; } default: ERROR("Unknown inode type %d in squashfs_iget!\n", type); return -EINVAL; } if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) { err = squashfs_xattr_lookup(sb, xattr_id, &squashfs_i(inode)->xattr_count, &squashfs_i(inode)->xattr_size, &squashfs_i(inode)->xattr); if (err < 0) goto failed_read; inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9) + 1; } else
static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result = NULL; int err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail1; hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_uid = current_fsuid(); result->i_gid = current_fsgid(); set_nlink(result, 1); result->i_size = 0; result->i_blocks = 1; init_special_inode(result, mode, rdev); r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = cpu_to_le32(dir->i_ino); mark_buffer_dirty(bh); insert_inode_hash(result); hpfs_write_inode_nolock(result); hpfs_update_directory_times(dir); d_instantiate(dentry, result); brelse(bh); hpfs_unlock(dir->i_sb); return 0; bail2: iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); return err; }
void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, int create_ino) { struct super_block *sb; struct ocfs2_super *osb; int use_plocks = 1; sb = inode->i_sb; osb = OCFS2_SB(sb); if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks()) use_plocks = 0; /* * These have all been checked by ocfs2_read_inode_block() or set * by ocfs2_mknod_locked(), so a failure is a code bug. */ BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); /* This means that read_inode cannot create a superblock inode today. change if that is needed. */ BUG_ON(!(fe->i_flags & cpu_to_le32(OCFS2_VALID_FL))); BUG_ON(le32_to_cpu(fe->i_fs_generation) != osb->fs_generation); OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); inode->i_version = 1; inode->i_generation = le32_to_cpu(fe->i_generation); inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); inode->i_mode = le16_to_cpu(fe->i_mode); i_uid_write(inode, le32_to_cpu(fe->i_uid)); i_gid_write(inode, le32_to_cpu(fe->i_gid)); /* Fast symlinks will have i_size but no allocated clusters. */ if (S_ISLNK(inode->i_mode) && !fe->i_clusters) { inode->i_blocks = 0; inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops; } else { inode->i_blocks = ocfs2_inode_sector_count(inode); inode->i_mapping->a_ops = &ocfs2_aops; } inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime); inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec); inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime); inode->i_mtime.tv_nsec = le32_to_cpu(fe->i_mtime_nsec); inode->i_ctime.tv_sec = le64_to_cpu(fe->i_ctime); inode->i_ctime.tv_nsec = le32_to_cpu(fe->i_ctime_nsec); if (OCFS2_I(inode)->ip_blkno != le64_to_cpu(fe->i_blkno)) mlog(ML_ERROR, "ip_blkno %llu != i_blkno %llu!\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)le64_to_cpu(fe->i_blkno)); set_nlink(inode, ocfs2_read_links_count(fe)); trace_ocfs2_populate_inode(OCFS2_I(inode)->ip_blkno, le32_to_cpu(fe->i_flags)); if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) { OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE; inode->i_flags |= S_NOQUOTA; } if (fe->i_flags & cpu_to_le32(OCFS2_LOCAL_ALLOC_FL)) { OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; } else if (fe->i_flags & cpu_to_le32(OCFS2_BITMAP_FL)) { OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; } else if (fe->i_flags & cpu_to_le32(OCFS2_QUOTA_FL)) { inode->i_flags |= S_NOQUOTA; } else if (fe->i_flags & cpu_to_le32(OCFS2_SUPER_BLOCK_FL)) { /* we can't actually hit this as read_inode can't * handle superblocks today ;-) */ BUG(); } switch (inode->i_mode & S_IFMT) { case S_IFREG: if (use_plocks) inode->i_fop = &ocfs2_fops; else inode->i_fop = &ocfs2_fops_no_plocks; inode->i_op = &ocfs2_file_iops; i_size_write(inode, le64_to_cpu(fe->i_size)); break; case S_IFDIR: inode->i_op = &ocfs2_dir_iops; if (use_plocks) inode->i_fop = &ocfs2_dops; else inode->i_fop = &ocfs2_dops_no_plocks; i_size_write(inode, le64_to_cpu(fe->i_size)); OCFS2_I(inode)->ip_dir_lock_gen = 1; break; case S_IFLNK: inode->i_op = &ocfs2_symlink_inode_operations; i_size_write(inode, le64_to_cpu(fe->i_size)); break; default: inode->i_op = &ocfs2_special_file_iops; init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } if (create_ino) { inode->i_ino = ino_from_blkno(inode->i_sb, le64_to_cpu(fe->i_blkno)); /* * If we ever want to create system files from kernel, * the generation argument to * ocfs2_inode_lock_res_init() will have to change. */ BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres, OCFS2_LOCK_TYPE_META, 0, inode); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres, OCFS2_LOCK_TYPE_OPEN, 0, inode); } ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres, OCFS2_LOCK_TYPE_RW, inode->i_generation, inode); ocfs2_set_inode_flags(inode); OCFS2_I(inode)->ip_last_used_slot = 0; OCFS2_I(inode)->ip_last_used_group = 0; if (S_ISDIR(inode->i_mode)) ocfs2_resv_set_type(&OCFS2_I(inode)->ip_la_data_resv, OCFS2_RESV_FLAG_DIR); }
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; jint16_t dev; int devlen = 0; uint32_t alloclen, phys_ofs; int ret; if (!old_valid_dev(rdev)) return -EINVAL; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = cpu_to_je16(old_encode_dev(rdev)); devlen = sizeof(dev); } /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_file_inode_operations; init_special_inode(inode, inode->i_mode, rdev); f = JFFS2_INODE_INFO(inode); ri->dsize = ri->csize = cpu_to_je32(devlen); ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; /* XXX: This is ugly. */ rd->type = (mode & S_IFMT) >> 12; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); jffs2_complete_reservation(c); d_instantiate(dentry, inode); return 0; }
static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(old_dentry); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, .dirtied_ino_d = ALIGN(ui->data_len, 8) }; struct fscrypt_name nm; /* * Budget request settings: new direntry, changing the target inode, * changing the parent inode. */ dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu", dentry, inode->i_ino, inode->i_nlink, dir->i_ino); ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); if (ubifs_crypt_is_encrypted(dir) && !fscrypt_has_permitted_context(dir, inode)) return -EPERM; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) return err; err = dbg_check_synced_i_size(c, inode); if (err) goto out_fname; err = ubifs_budget_space(c, &req); if (err) goto out_fname; lock_2_inodes(dir, inode); /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */ if (inode->i_nlink == 0) ubifs_delete_orphan(c, inode->i_ino); inc_nlink(inode); ihold(inode); inode->i_ctime = current_time(inode); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); if (inode->i_nlink == 0) ubifs_add_orphan(c, inode->i_ino); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode); out_fname: fscrypt_free_filename(&nm); return err; } static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change, budgeted = 1; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; unsigned int saved_nlink = inode->i_nlink; struct fscrypt_name nm; /* * Budget request settings: deletion direntry, deletion inode (+1 for * @dirtied_ino), changing the parent directory inode. If budgeting * fails, go ahead anyway because we have extra space reserved for * deletions. */ dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu", dentry, inode->i_ino, inode->i_nlink, dir->i_ino); if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err && err != -ENOKEY) return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); if (err) return err; sz_change = CALC_DENT_SIZE(fname_len(&nm)); ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); err = dbg_check_synced_i_size(c, inode); if (err) goto out_fname; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) goto out_fname; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = current_time(dir); drop_nlink(inode); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; set_nlink(inode, saved_nlink); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); out_fname: fscrypt_free_filename(&nm); return err; } /** * check_dir_empty - check if a directory is empty or not. * @dir: VFS inode object of the directory to check * * This function checks if directory @dir is empty. Returns zero if the * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes * in case of of errors. */ int ubifs_check_dir_empty(struct inode *dir) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct fscrypt_name nm = { 0 }; struct ubifs_dent_node *dent; union ubifs_key key; int err; lowest_dent_key(c, &key, dir->i_ino); dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -ENOENT) err = 0; } else { kfree(dent); err = -ENOTEMPTY; } return err; } static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); int err, sz_change, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; struct fscrypt_name nm; /* * Budget request settings: deletion direntry, deletion inode and * changing the parent inode. If budgeting fails, go ahead anyway * because we have extra space reserved for deletions. */ dbg_gen("directory '%pd', ino %lu in dir ino %lu", dentry, inode->i_ino, dir->i_ino); ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); err = ubifs_check_dir_empty(d_inode(dentry)); if (err) return err; if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err && err != -ENOKEY) return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); if (err) return err; sz_change = CALC_DENT_SIZE(fname_len(&nm)); err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) goto out_fname; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = current_time(dir); clear_nlink(inode); drop_nlink(dir); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(dir); set_nlink(inode, 2); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); out_fname: fscrypt_free_filename(&nm); return err; } static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; struct fscrypt_name nm; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) goto out_budg; sz_change = CALC_DENT_SIZE(fname_len(&nm)); inode = ubifs_new_inode(c, dir, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fname; } err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); inc_nlink(dir); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) { ubifs_err(c, "cannot create directory, error %d", err); goto out_cancel; } mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(dir); mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; union ubifs_dev_desc *dev = NULL; int sz_change; int err, devlen = 0; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .dirtied_ino = 1 }; struct fscrypt_name nm; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) return -ENOMEM; devlen = ubifs_encode_dev(dev, rdev); } req.new_ino_d = ALIGN(devlen, 8); err = ubifs_budget_space(c, &req); if (err) { kfree(dev); return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) { kfree(dev); goto out_budg; } sz_change = CALC_DENT_SIZE(fname_len(&nm)); inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { kfree(dev); err = PTR_ERR(inode); goto out_fname; } init_special_inode(inode, inode->i_mode, rdev); inode->i_size = ubifs_inode(inode)->ui_size = devlen; ui = ubifs_inode(inode); ui->data = dev; ui->data_len = devlen; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(len); struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); struct fscrypt_symlink_data *sd = NULL; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; struct fscrypt_name nm; if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err) goto out_budg; if (!fscrypt_has_encryption_key(dir)) { err = -EPERM; goto out_budg; } disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + sizeof(struct fscrypt_symlink_data)); } /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, symname, dir->i_ino); if (disk_link.len > UBIFS_MAX_INO_DATA) return -ENAMETOOLONG; err = ubifs_budget_space(c, &req); if (err) return err; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) goto out_budg; inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fname; } ui = ubifs_inode(inode); ui->data = kmalloc(disk_link.len, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_inode; } if (ubifs_crypt_is_encrypted(dir)) { struct qstr istr = QSTR_INIT(symname, len); struct fscrypt_str ostr; sd = kzalloc(disk_link.len, GFP_NOFS); if (!sd) { err = -ENOMEM; goto out_inode; } ostr.name = sd->encrypted_path; ostr.len = disk_link.len; err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); if (err) { kfree(sd); goto out_inode; } sd->len = cpu_to_le16(ostr.len); disk_link.name = (char *)sd; } else { inode->i_link = ui->data; } memcpy(ui->data, disk_link.name, disk_link.len); ((char *)ui->data)[disk_link.len - 1] = '\0'; /* * The terminating zero byte is not written to the flash media and it * is put just to make later in-memory string processing simpler. Thus, * data length is @len, not @len + %1. */ ui->data_len = disk_link.len - 1; inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } /** * lock_4_inodes - a wrapper for locking three UBIFS inodes. * @inode1: first inode * @inode2: second inode * @inode3: third inode * @inode4: fouth inode * * This function is used for 'ubifs_rename()' and @inode1 may be the same as * @inode2 whereas @inode3 and @inode4 may be %NULL. * * We do not implement any tricks to guarantee strict lock ordering, because * VFS has already done it for us on the @i_mutex. So this is just a simple * wrapper function. */ static void lock_4_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3, struct inode *inode4) { mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); if (inode2 != inode1) mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); if (inode3) mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3); if (inode4) mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4); } /** * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode * @inode4: fouth inode */ static void unlock_4_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3, struct inode *inode4) { if (inode4) mutex_unlock(&ubifs_inode(inode4)->ui_mutex); if (inode3) mutex_unlock(&ubifs_inode(inode3)->ui_mutex); if (inode1 != inode2) mutex_unlock(&ubifs_inode(inode2)->ui_mutex); mutex_unlock(&ubifs_inode(inode1)->ui_mutex); } static int do_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); struct inode *whiteout = NULL; struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); struct ubifs_inode *whiteout_ui = NULL; int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); int unlink = !!new_inode, new_sz, old_sz; struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 3 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; unsigned int uninitialized_var(saved_nlink); struct fscrypt_name old_nm, new_nm; /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. * * However, this operation also marks the target inode as dirty and * does not write it, so we allocate budget for the target inode * separately. */ dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x", old_dentry, old_inode->i_ino, old_dir->i_ino, new_dentry, new_dir->i_ino, flags); if (unlink) ubifs_assert(inode_is_locked(new_inode)); if (old_dir != new_dir) { if (ubifs_crypt_is_encrypted(new_dir) && !fscrypt_has_permitted_context(new_dir, old_inode)) return -EPERM; } if (unlink && is_dir) { err = ubifs_check_dir_empty(new_inode); if (err) return err; } err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm); if (err) return err; err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm); if (err) { fscrypt_free_filename(&old_nm); return err; } new_sz = CALC_DENT_SIZE(fname_len(&new_nm)); old_sz = CALC_DENT_SIZE(fname_len(&old_nm)); err = ubifs_budget_space(c, &req); if (err) { fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; } err = ubifs_budget_space(c, &ino_req); if (err) { fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); ubifs_release_budget(c, &req); return err; } if (flags & RENAME_WHITEOUT) { union ubifs_dev_desc *dev = NULL; dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) { err = -ENOMEM; goto out_release; } err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout); if (err) { kfree(dev); goto out_release; } whiteout->i_state |= I_LINKABLE; whiteout_ui = ubifs_inode(whiteout); whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); ubifs_assert(!whiteout_ui->dirty); } lock_4_inodes(old_dir, new_dir, new_inode, whiteout); /* * Like most other Unix systems, set the @i_ctime for inodes on a * rename. */ time = current_time(old_dir); old_inode->i_ctime = time; /* We must adjust parent link count when renaming directories */ if (is_dir) { if (move) { /* * @old_dir loses a link because we are moving * @old_inode to a different directory. */ drop_nlink(old_dir); /* * @new_dir only gains a link if we are not also * overwriting an existing directory. */ if (!unlink) inc_nlink(new_dir); } else { /* * @old_inode is not moving to a different directory, * but @old_dir still loses a link if we are * overwriting an existing directory. */ if (unlink) drop_nlink(old_dir); } } old_dir->i_size -= old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; /* * And finally, if we unlinked a direntry which happened to have the * same name as the moved direntry, we have to decrement @i_nlink of * the unlinked inode and change its ctime. */ if (unlink) { /* * Directories cannot have hard-links, so if this is a * directory, just clear @i_nlink. */ saved_nlink = new_inode->i_nlink; if (is_dir) clear_nlink(new_inode); else drop_nlink(new_inode); new_inode->i_ctime = time; } else { new_dir->i_size += new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } /* * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode * is dirty, because this will be done later on at the end of * 'ubifs_rename()'. */ if (IS_SYNC(old_inode)) { sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); if (unlink && IS_SYNC(new_inode)) sync = 1; } if (whiteout) { struct ubifs_budget_req wht_req = { .dirtied_ino = 1, .dirtied_ino_d = \ ALIGN(ubifs_inode(whiteout)->data_len, 8) }; err = ubifs_budget_space(c, &wht_req); if (err) { kfree(whiteout_ui->data); whiteout_ui->data_len = 0; iput(whiteout); goto out_release; } inc_nlink(whiteout); mark_inode_dirty(whiteout); whiteout->i_state &= ~I_LINKABLE; iput(whiteout); } err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, new_inode, &new_nm, whiteout, sync); if (err) goto out_cancel; unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); ubifs_release_budget(c, &req); mutex_lock(&old_inode_ui->ui_mutex); release = old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); mutex_unlock(&old_inode_ui->ui_mutex); if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) err = old_inode->i_sb->s_op->write_inode(old_inode, NULL); fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; out_cancel: if (unlink) { set_nlink(new_inode, saved_nlink); } else { new_dir->i_size -= new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } old_dir->i_size += old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; if (is_dir) { if (move) { inc_nlink(old_dir); if (!unlink) drop_nlink(new_dir); } else { if (unlink) inc_nlink(old_dir); } } if (whiteout) { drop_nlink(whiteout); iput(whiteout); } unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); out_release: ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; } static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 2 }; int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); struct inode *fst_inode = d_inode(old_dentry); struct inode *snd_inode = d_inode(new_dentry); struct timespec time; int err; struct fscrypt_name fst_nm, snd_nm; ubifs_assert(fst_inode && snd_inode); if ((ubifs_crypt_is_encrypted(old_dir) || ubifs_crypt_is_encrypted(new_dir)) && (old_dir != new_dir) && (!fscrypt_has_permitted_context(new_dir, fst_inode) || !fscrypt_has_permitted_context(old_dir, snd_inode))) return -EPERM; err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); if (err) return err; err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm); if (err) { fscrypt_free_filename(&fst_nm); return err; } lock_4_inodes(old_dir, new_dir, NULL, NULL); time = current_time(old_dir); fst_inode->i_ctime = time; snd_inode->i_ctime = time; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; if (old_dir != new_dir) { if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { inc_nlink(new_dir); drop_nlink(old_dir); } else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { drop_nlink(new_dir); inc_nlink(old_dir); } } err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir, snd_inode, &snd_nm, sync); unlock_4_inodes(old_dir, new_dir, NULL, NULL); ubifs_release_budget(c, &req); fscrypt_free_filename(&fst_nm); fscrypt_free_filename(&snd_nm); return err; } static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE)) return -EINVAL; ubifs_assert(inode_is_locked(old_dir)); ubifs_assert(inode_is_locked(new_dir)); if (flags & RENAME_EXCHANGE) return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } int ubifs_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { loff_t size; struct inode *inode = d_inode(path->dentry); struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); if (ui->flags & UBIFS_APPEND_FL) stat->attributes |= STATX_ATTR_APPEND; if (ui->flags & UBIFS_COMPR_FL) stat->attributes |= STATX_ATTR_COMPRESSED; if (ui->flags & UBIFS_CRYPT_FL) stat->attributes |= STATX_ATTR_ENCRYPTED; if (ui->flags & UBIFS_IMMUTABLE_FL) stat->attributes |= STATX_ATTR_IMMUTABLE; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE); generic_fillattr(inode, stat); stat->blksize = UBIFS_BLOCK_SIZE; stat->size = ui->ui_size; /* * Unfortunately, the 'stat()' system call was designed for block * device based file systems, and it is not appropriate for UBIFS, * because UBIFS does not have notion of "block". For example, it is * difficult to tell how many block a directory takes - it actually * takes less than 300 bytes, but we have to round it to block size, * which introduces large mistake. This makes utilities like 'du' to * report completely senseless numbers. This is the reason why UBIFS * goes the same way as JFFS2 - it reports zero blocks for everything * but regular files, which makes more sense than reporting completely * wrong sizes. */ if (S_ISREG(inode->i_mode)) { size = ui->xattr_size; size += stat->size; size = ALIGN(size, UBIFS_BLOCK_SIZE); /* * Note, user-space expects 512-byte blocks count irrespectively * of what was reported in @stat->size. */ stat->blocks = size >> 9; } else stat->blocks = 0; mutex_unlock(&ui->ui_mutex); return 0; } static int ubifs_dir_open(struct inode *dir, struct file *file) { if (ubifs_crypt_is_encrypted(dir)) return fscrypt_get_encryption_info(dir) ? -EACCES : 0; return 0; } const struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, .create = ubifs_create, .link = ubifs_link, .symlink = ubifs_symlink, .unlink = ubifs_unlink, .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, .listxattr = ubifs_listxattr, #ifdef CONFIG_UBIFS_ATIME_SUPPORT .update_time = ubifs_update_time, #endif .tmpfile = ubifs_tmpfile, }; const struct file_operations ubifs_dir_operations = { .llseek = generic_file_llseek, .release = ubifs_dir_release, .read = generic_read_dir, .iterate_shared = ubifs_readdir, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, .open = ubifs_dir_open, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif };