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; ext2_inc_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; ext2_inc_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); out: return err; out_fail: ext2_dec_count(inode); ext2_dec_count(inode); iput(inode); out_dir: ext2_dec_count(dir); goto out; }
static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; nid_t ino = 0; int err; err = dquot_initialize(dir); if (err) return err; inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) set_cold_files(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; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out; f2fs_unlock_op(sbi); alloc_nid_done(sbi, ino); d_instantiate(dentry, inode); unlock_new_inode(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); f2fs_balance_fs(sbi, true); return 0; out: handle_failed_inode(inode); return err; }
static int ext2_setup_super (struct super_block * sb, struct ext2_super_block * es, int read_only) { int res = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { printk ("EXT2-fs warning: revision level too high, " "forcing read-only mode\n"); res = MS_RDONLY; } if (read_only) return res; if (!(sbi->s_mount_state & EXT2_VALID_FS)) printk ("EXT2-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); else if ((sbi->s_mount_state & EXT2_ERROR_FS)) printk ("EXT2-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && le16_to_cpu(es->s_mnt_count) >= (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) printk ("EXT2-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (le32_to_cpu(es->s_checkinterval) && (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= get_seconds())) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); if (!le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); le16_add_cpu(&es->s_mnt_count, 1); ext2_write_super(sb); if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, sbi->s_frag_size, sbi->s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), sbi->s_mount_opt); return res; }
static int f2fs_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct f2fs_sb_info *sbi = F2FS_SB(vfs->mnt_sb); if (!(vfs->mnt_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC)) seq_printf(seq, ",background_gc=%s", "on"); else seq_printf(seq, ",background_gc=%s", "off"); if (test_opt(sbi, DISABLE_ROLL_FORWARD)) seq_puts(seq, ",disable_roll_forward"); if (test_opt(sbi, DISCARD)) seq_puts(seq, ",discard"); if (test_opt(sbi, NOHEAP)) seq_puts(seq, ",no_heap_alloc"); #ifdef CONFIG_F2FS_FS_XATTR if (test_opt(sbi, XATTR_USER)) seq_puts(seq, ",user_xattr"); else seq_puts(seq, ",nouser_xattr"); if (test_opt(sbi, INLINE_XATTR)) seq_puts(seq, ",inline_xattr"); #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL if (test_opt(sbi, POSIX_ACL)) seq_puts(seq, ",acl"); else seq_puts(seq, ",noacl"); #endif if (test_opt(sbi, DISABLE_EXT_IDENTIFY)) seq_puts(seq, ",disable_ext_identify"); if (test_opt(sbi, INLINE_DATA)) seq_puts(seq, ",inline_data"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); return 0; }
static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode = ext2_new_inode(dir, mode, NULL); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; 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); d_tmpfile(dentry, inode); unlock_new_inode(inode); return 0; }
bool f2fs_may_inline_data(struct inode *inode) { if (!test_opt(F2FS_I_SB(inode), INLINE_DATA)) return false; if (f2fs_is_atomic_file(inode)) return false; if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) return false; if (i_size_read(inode) > MAX_INLINE_DATA) return false; if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) return false; return true; }
static int ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct inode *inode = dentry->d_inode; handle_t *handle; struct posix_acl *acl; int error, retries = 0; if (strcmp(name, "") != 0) return -EINVAL; if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; if (!inode_owner_or_capable(inode)) return -EPERM; if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); else if (acl) { error = posix_acl_valid(acl); if (error) goto release_and_out; } } else acl = NULL; retry: handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) { error = PTR_ERR(handle); goto release_and_out; } error = ext4_set_acl(handle, inode, type, acl); ext4_journal_stop(handle); if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; release_and_out: posix_acl_release(acl); return error; }
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; 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: ext2_dec_count(inode); iput (inode); goto out; }
static int ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) { struct posix_acl *acl; int error; if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; acl = ext3_get_acl(inode, type); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) return -ENODATA; error = posix_acl_to_xattr(acl, buffer, size); posix_acl_release(acl); return error; }
bool f2fs_may_inline(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); block_t nr_blocks; loff_t i_size; if (!test_opt(sbi, INLINE_DATA)) return false; nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2; if (inode->i_blocks > nr_blocks) return false; i_size = i_size_read(inode); if (i_size > MAX_INLINE_DATA) return false; return true; }
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; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) set_cold_files(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; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); f2fs_unlock_op(sbi); if (err) goto out; alloc_nid_done(sbi, 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, ino); return err; }
static int ext3_xattr_user_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { int error; if (strcmp(name, "") == 0) return -EINVAL; if (!test_opt(inode->i_sb, XATTR_USER)) return -EOPNOTSUPP; if ( !S_ISREG(inode->i_mode) && (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) return -EPERM; error = permission(inode, MAY_WRITE, NULL); if (error) return error; return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name, value, size, flags); }
long ext4_set_gps_location(struct inode *inode) { struct gps_location loc; struct ext4_inode_info *iinfo = EXT4_I(inode); long ts; if (!test_opt(inode->i_sb, GPS_AWARE_INODE)) return -ENODEV; kget_gps_location(&loc, &ts); ts = CURRENT_TIME_SEC.tv_sec - ts; write_lock(&iinfo->i_gps_lock); memcpy(&iinfo->i_latitude, &loc.latitude, sizeof(long long)); memcpy(&iinfo->i_longitude, &loc.longitude, sizeof(long long)); memcpy(&iinfo->i_accuracy, &loc.accuracy, sizeof(long)); memcpy(&iinfo->i_coord_age, &ts, sizeof(long)); write_unlock(&iinfo->i_gps_lock); return 0; }
/* * Does chmod for an inode that may have an Access Control List. The * inode->i_mode field must be updated to the desired value by the caller * before calling this function. * Returns 0 on success, or a negative error number. * * We change the ACL rather than storing some ACL entries in the file * mode permission bits (which would be more efficient), because that * would break once additional permissions (like ACL_APPEND, ACL_DELETE * for directories) are added. There are no more bits available in the * file mode. * * inode->i_mutex: down */ int ext2_acl_chmod(struct inode *inode) { struct posix_acl *acl; int error; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); return error; }
bool f2fs_may_inline(struct inode *inode) { block_t nr_blocks; loff_t i_size; if (!test_opt(F2FS_I_SB(inode), INLINE_DATA)) return false; if (f2fs_is_atomic_file(inode)) return false; nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2; if (inode->i_blocks > nr_blocks) return false; i_size = i_size_read(inode); if (i_size > MAX_INLINE_DATA) return false; return true; }
/* * 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 = ext2_new_inode (dir, mode); int err = PTR_ERR(inode); if (!IS_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); err = ext2_add_nondir(dentry, inode); } return err; }
/* * 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, umode_t mode, bool excl) { struct inode *inode; dquot_initialize(dir); inode = ext2_new_inode(dir, mode, &dentry->d_name); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; 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); }
void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type, int rw) { enum page_type btype = PAGE_TYPE_OF_BIO(type); struct f2fs_bio_info *io; io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype]; down_write(&io->io_rwsem); /* change META to META_FLUSH in the checkpoint procedure */ if (type >= META_FLUSH) { io->fio.type = META_FLUSH; if (test_opt(sbi, NOBARRIER)) io->fio.rw = WRITE_FLUSH | REQ_META | REQ_PRIO; else io->fio.rw = WRITE_FLUSH_FUA | REQ_META | REQ_PRIO; } __submit_merged_bio(io); up_write(&io->io_rwsem); }
static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); struct inode *inode = dentry->d_inode; struct posix_acl *acl = NULL; int error; if (!test_opt(sbi, POSIX_ACL)) return -EOPNOTSUPP; if (strcmp(name, "") != 0) return -EINVAL; /* * 2.6.35 uses is_owner_or_cap() instead of inode_owner_or_capable() * -- marc1706 */ if (!is_owner_or_cap(inode)) return -EPERM; if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { error = posix_acl_valid(acl); if (error) goto release_and_out; } } else { acl = NULL; } error = f2fs_set_acl(inode, type, acl); release_and_out: posix_acl_release(acl); return error; }
struct posix_acl *f2fs_get_acl(struct inode *inode, int type) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; void *value = NULL; struct posix_acl *acl; int retval; if (!test_opt(sbi, POSIX_ACL)) return NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; if (type == ACL_TYPE_ACCESS) name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; retval = f2fs_getxattr(inode, name_index, "", NULL, 0); if (retval > 0) { value = kmalloc(retval, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); retval = f2fs_getxattr(inode, name_index, "", value, retval); } if (retval < 0) { if (retval == -ENODATA) acl = NULL; else acl = ERR_PTR(retval); } else { acl = f2fs_acl_from_disk(value, retval); } kfree(value); if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); return acl; }
/* * Does chmod for an inode that may have an Access Control List. The * inode->i_mode field must be updated to the desired value by the caller * before calling this function. * Returns 0 on success, or a negative error number. * * We change the ACL rather than storing some ACL entries in the file * mode permission bits (which would be more efficient), because that * would break once additional permissions (like ACL_APPEND, ACL_DELETE * for directories) are added. There are no more bits available in the * file mode. * * inode->i_mutex: down */ int ext3_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); if (!clone) return -ENOMEM; error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) { handle_t *handle; int retries = 0; retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) { error = PTR_ERR(handle); ext3_std_error(inode->i_sb, error); goto out; } error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); ext3_journal_stop(handle); if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; } out: posix_acl_release(clone); return error; }
static int ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { struct posix_acl *acl; int error; if (strcmp(name, "") != 0) return -EINVAL; if (!test_opt(dentry->d_sb, POSIX_ACL)) return -EOPNOTSUPP; acl = ext4_get_acl(dentry->d_inode, type); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) return -ENODATA; error = posix_acl_to_xattr(acl, buffer, size); posix_acl_release(acl); return error; }
void opt(char **av, char *tabb) { int i; int y; int bo; i = 1; my_bzero(tabb, 3); while (av[i] != NULL && av[i][0] == '-') { y = 0; if (av[i][y] == '-') bo = test_opt(av, tabb, y, i); if (bo == 1) { my_putstr(av[i], 1); if (av[i + 1] != NULL && tabb[2] != 's') my_putchar(' ', 1); } i++; } }
static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); struct posix_acl *acl; int error; if (strcmp(name, "") != 0) return -EINVAL; if (!test_opt(sbi, POSIX_ACL)) return -EOPNOTSUPP; acl = f2fs_get_acl(dentry->d_inode, type); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) return -ENODATA; error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); posix_acl_release(acl); return error; }
static inline bool need_do_checkpoint(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); bool need_cp = false; if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) need_cp = true; else if (file_wrong_pino(inode)) need_cp = true; else if (!space_for_roll_forward(sbi)) need_cp = true; else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) need_cp = true; else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) need_cp = true; else if (test_opt(sbi, FASTBOOT)) need_cp = true; else if (sbi->active_logs == 2) need_cp = true; return need_cp; }
static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); switch (type) { case F2FS_XATTR_INDEX_USER: if (!test_opt(sbi, XATTR_USER)) return -EOPNOTSUPP; break; case F2FS_XATTR_INDEX_TRUSTED: if (!capable(CAP_SYS_ADMIN)) return -EPERM; break; default: return -EINVAL; } if (strcmp(name, "") == 0) return -EINVAL; return f2fs_setxattr(dentry->d_inode, type, name, value, size); }
static int ext3_xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) { handle_t *handle; struct posix_acl *acl; int error, retries = 0; if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); else if (acl) { error = posix_acl_valid(acl); if (error) goto release_and_out; } } else acl = NULL; retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); error = ext3_set_acl(handle, inode, type, acl); ext3_journal_stop(handle); if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; release_and_out: posix_acl_release(acl); return error; }
static int f2fs_xattr_generic_get(const struct xattr_handler *handler, struct dentry *unused, struct inode *inode, const char *name, void *buffer, size_t size) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); switch (handler->flags) { case F2FS_XATTR_INDEX_USER: if (!test_opt(sbi, XATTR_USER)) return -EOPNOTSUPP; break; case F2FS_XATTR_INDEX_TRUSTED: if (!capable(CAP_SYS_ADMIN)) return -EPERM; break; case F2FS_XATTR_INDEX_SECURITY: break; default: return -EINVAL; } return f2fs_getxattr(inode, handler->flags, name, buffer, size, NULL); }
int f2fs_acl_chmod(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct posix_acl *acl; int error; mode_t mode = get_inode_mode(inode); if (!test_opt(sbi, POSIX_ACL)) return 0; if (S_ISLNK(mode)) return -EOPNOTSUPP; acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); error = posix_acl_chmod(&acl, GFP_KERNEL, mode); if (error) return error; error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); return error; }
/* * Does chmod for an inode that may have an Access Control List. The * inode->i_mode field must be updated to the desired value by the caller * before calling this function. * Returns 0 on success, or a negative error number. * * We change the ACL rather than storing some ACL entries in the file * mode permission bits (which would be more efficient), because that * would break once additional permissions (like ACL_APPEND, ACL_DELETE * for directories) are added. There are no more bits available in the * file mode. * * inode->i_mutex: down */ int ext2_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int error; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); if (!clone) return -ENOMEM; error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) error = ext2_set_acl(inode, ACL_TYPE_ACCESS, clone); posix_acl_release(clone); return error; }