lkml.org 
[lkml]   [2012]   [Oct]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 11/16 v2] f2fs: add inode operations for special inodes
    Date
    This adds inode operations for directory, symlink, and special inodes.

    Signed-off-by: Changman Lee <cm224.lee@samsung.com>
    Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
    ---
    fs/f2fs/namei.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
    1 file changed, 494 insertions(+)
    create mode 100644 fs/f2fs/namei.c

    diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
    new file mode 100644
    index 0000000..899d144
    --- /dev/null
    +++ b/fs/f2fs/namei.c
    @@ -0,0 +1,494 @@
    +/**
    + * fs/f2fs/namei.c
    + *
    + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
    + * http://www.samsung.com/
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/fs.h>
    +#include <linux/f2fs_fs.h>
    +#include <linux/pagemap.h>
    +#include <linux/sched.h>
    +#include <linux/ctype.h>
    +
    +#include "f2fs.h"
    +#include "xattr.h"
    +#include "acl.h"
    +
    +static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
    +{
    + struct super_block *sb = dir->i_sb;
    + struct f2fs_sb_info *sbi = F2FS_SB(sb);
    + nid_t ino;
    + struct inode *inode;
    + bool nid_free = false;
    + int err;
    +
    + inode = new_inode(sb);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    +
    + mutex_lock_op(sbi, NODE_NEW);
    + if (!alloc_nid(sbi, &ino)) {
    + mutex_unlock_op(sbi, NODE_NEW);
    + err = -ENOSPC;
    + goto fail;
    + }
    + mutex_unlock_op(sbi, NODE_NEW);
    +
    + inode->i_uid = current_fsuid();
    +
    + if (dir->i_mode & S_ISGID) {
    + inode->i_gid = dir->i_gid;
    + if (S_ISDIR(mode))
    + mode |= S_ISGID;
    + } else {
    + inode->i_gid = current_fsgid();
    + }
    +
    + inode->i_ino = ino;
    + inode->i_mode = mode;
    + inode->i_blocks = 0;
    + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
    +
    + err = insert_inode_locked(inode);
    + if (err) {
    + err = -EINVAL;
    + nid_free = true;
    + goto out;
    + }
    +
    + mark_inode_dirty(inode);
    + return inode;
    +
    +out:
    + clear_nlink(inode);
    + unlock_new_inode(inode);
    +fail:
    + iput(inode);
    + if (nid_free)
    + alloc_nid_failed(sbi, ino);
    + return ERR_PTR(err);
    +}
    +
    +static int is_multimedia_file(const unsigned char *s, const char *sub)
    +{
    + int slen = strlen(s);
    + int sublen = strlen(sub);
    + int ret;
    +
    + if (sublen > slen)
    + return 1;
    +
    + ret = memcmp(s + slen - sublen, sub, sublen);
    + if (ret) { /* compare upper case */
    + int i;
    + char upper_sub[8];
    + for (i = 0; i < sublen && i < sizeof(upper_sub); i++)
    + upper_sub[i] = toupper(sub[i]);
    + return memcmp(s + slen - sublen, upper_sub, sublen);
    + }
    +
    + return ret;
    +}
    +
    +/**
    + * Set multimedia files as cold files for hot/cold data separation
    + */
    +static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode,
    + const unsigned char *name)
    +{
    + int i;
    + __u8 (*extlist)[8] = sbi->raw_super->extension_list;
    +
    + int count = le32_to_cpu(sbi->raw_super->extension_count);
    + for (i = 0; i < count; i++) {
    + if (!is_multimedia_file(name, extlist[i])) {
    + F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT;
    + break;
    + }
    + }
    +}
    +
    +static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
    + bool excl)
    +{
    + struct super_block *sb = dir->i_sb;
    + struct f2fs_sb_info *sbi = F2FS_SB(sb);
    + struct inode *inode;
    + nid_t ino = 0;
    + int err;
    +
    + inode = f2fs_new_inode(dir, mode);
    + if (IS_ERR(inode))
    + return PTR_ERR(inode);
    +
    + if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
    + set_cold_file(sbi, inode, dentry->d_name.name);
    +
    + inode->i_op = &f2fs_file_inode_operations;
    + inode->i_fop = &f2fs_file_operations;
    + inode->i_mapping->a_ops = &f2fs_dblock_aops;
    + ino = inode->i_ino;
    +
    + err = f2fs_add_link(dentry, inode);
    + if (err)
    + goto out;
    +
    + alloc_nid_done(sbi, ino);
    +
    + if (!sbi->por_doing)
    + d_instantiate(dentry, inode);
    + unlock_new_inode(inode);
    +
    + f2fs_balance_fs(sbi);
    + return 0;
    +out:
    + clear_nlink(inode);
    + unlock_new_inode(inode);
    + iput(inode);
    + alloc_nid_failed(sbi, ino);
    + return err;
    +}
    +
    +static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
    + struct dentry *dentry)
    +{
    + struct inode *inode = old_dentry->d_inode;
    + struct super_block *sb = dir->i_sb;
    + struct f2fs_sb_info *sbi = F2FS_SB(sb);
    + int err;
    +
    + inode->i_ctime = CURRENT_TIME;
    + atomic_inc(&inode->i_count);
    +
    + set_inode_flag(F2FS_I(inode), FI_INC_LINK);
    + err = f2fs_add_link(dentry, inode);
    + if (err)
    + goto out;
    +
    + d_instantiate(dentry, inode);
    +
    + f2fs_balance_fs(sbi);
    + return 0;
    +out:
    + clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
    + iput(inode);
    + return err;
    +}
    +
    +static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
    + unsigned int flags)
    +{
    + struct inode *inode = NULL;
    + struct f2fs_dir_entry *de;
    + struct page *page;
    +
    + if (dentry->d_name.len > F2FS_MAX_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;
    +
    + de = f2fs_find_entry(dir, &dentry->d_name, &page);
    + if (!de)
    + goto fail;
    +
    + err = check_orphan_space(sbi);
    + if (err) {
    + kunmap(page);
    + f2fs_put_page(page, 0);
    + goto fail;
    + }
    +
    + f2fs_delete_entry(de, page, inode);
    +
    + /* In order to evict this inode, we set it dirty */
    + mark_inode_dirty(inode);
    + f2fs_balance_fs(sbi);
    +fail:
    + 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;
    + unsigned symlen = strlen(symname) + 1;
    + int err;
    +
    + 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;
    +
    + err = f2fs_add_link(dentry, inode);
    + 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);
    +
    + f2fs_balance_fs(sbi);
    +
    + return err;
    +out:
    + clear_nlink(inode);
    + unlock_new_inode(inode);
    + iput(inode);
    + alloc_nid_failed(sbi, inode->i_ino);
    + return err;
    +}
    +
    +static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
    +{
    + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
    + struct inode *inode;
    + int err;
    +
    + inode = f2fs_new_inode(dir, S_IFDIR | mode);
    + err = PTR_ERR(inode);
    + if (IS_ERR(inode))
    + return err;
    +
    + 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_NOFS | __GFP_ZERO);
    +
    + set_inode_flag(F2FS_I(inode), FI_INC_LINK);
    + err = f2fs_add_link(dentry, inode);
    + if (err)
    + goto out_fail;
    +
    + alloc_nid_done(sbi, inode->i_ino);
    +
    + d_instantiate(dentry, inode);
    + unlock_new_inode(inode);
    +
    + f2fs_balance_fs(sbi);
    + return 0;
    +
    +out_fail:
    + clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
    + clear_nlink(inode);
    + unlock_new_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,
    + umode_t 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;
    +
    + 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;
    +
    + err = f2fs_add_link(dentry, inode);
    + if (err)
    + goto out;
    +
    + alloc_nid_done(sbi, inode->i_ino);
    + d_instantiate(dentry, inode);
    + unlock_new_inode(inode);
    +
    + f2fs_balance_fs(sbi);
    +
    + return 0;
    +out:
    + clear_nlink(inode);
    + unlock_new_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;
    + struct f2fs_dir_entry *old_dir_entry = NULL;
    + struct f2fs_dir_entry *old_entry;
    + struct f2fs_dir_entry *new_entry;
    + int err = -ENOENT;
    +
    + 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;
    + }
    +
    + mutex_lock_op(sbi, RENAME);
    +
    + if (new_inode) {
    + struct page *new_page;
    +
    + 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;
    +
    + f2fs_set_link(new_dir, new_entry, new_page, old_inode);
    +
    + new_inode->i_ctime = CURRENT_TIME;
    + if (old_dir_entry)
    + drop_nlink(new_inode);
    + drop_nlink(new_inode);
    + if (!new_inode->i_nlink)
    + add_orphan_inode(sbi, new_inode->i_ino);
    + f2fs_write_inode(new_inode, NULL);
    + } else {
    + err = f2fs_add_link(new_dentry, old_inode);
    + if (err)
    + goto out_dir;
    +
    + if (old_dir_entry) {
    + inc_nlink(new_dir);
    + f2fs_write_inode(new_dir, NULL);
    + }
    + }
    +
    + old_inode->i_ctime = CURRENT_TIME;
    + set_inode_flag(F2FS_I(old_inode), FI_NEED_CP);
    + 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);
    + } else {
    + kunmap(old_dir_page);
    + f2fs_put_page(old_dir_page, 0);
    + }
    + drop_nlink(old_dir);
    + f2fs_write_inode(old_dir, NULL);
    + }
    +
    + mutex_unlock_op(sbi, RENAME);
    +
    + f2fs_balance_fs(sbi);
    + return 0;
    +
    +out_dir:
    + if (old_dir_entry) {
    + kunmap(old_dir_page);
    + f2fs_put_page(old_dir_page, 0);
    + }
    + mutex_unlock_op(sbi, RENAME);
    +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,
    + .setattr = f2fs_setattr,
    + .get_acl = f2fs_get_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,
    + .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 = {
    + .setattr = f2fs_setattr,
    + .get_acl = f2fs_get_acl,
    +#ifdef CONFIG_F2FS_FS_XATTR
    + .setxattr = generic_setxattr,
    + .getxattr = generic_getxattr,
    + .listxattr = f2fs_listxattr,
    + .removexattr = generic_removexattr,
    +#endif
    +};
    --
    1.7.9.5



    ---
    Jaegeuk Kim
    Samsung




    \
     
     \ /
      Last update: 2012-10-23 05:21    [W:4.087 / U:0.216 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site