From b22e8fedc19588864a6ba0acefbbed06f05ba713 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 29 Nov 2013 22:51:47 -0500 Subject: ecryptfs: fix failure handling in ->readlink() If ecryptfs_readlink_lower() fails, buf remains an uninitialized pointer and passing it nd_set_link() won't do anything good. Fixed by switching ecryptfs_readlink_lower() to saner API - make it return buf or ERR_PTR(...) and update callers. Signed-off-by: Al Viro diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index c36c448..b167ca4 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -659,19 +659,17 @@ out_lock: return rc; } -static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, - size_t *bufsiz) +static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); char *lower_buf; + char *buf; mm_segment_t old_fs; int rc; lower_buf = kmalloc(PATH_MAX, GFP_KERNEL); - if (!lower_buf) { - rc = -ENOMEM; - goto out; - } + if (!lower_buf) + return ERR_PTR(-ENOMEM); old_fs = get_fs(); set_fs(get_ds()); rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, @@ -680,21 +678,18 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, set_fs(old_fs); if (rc < 0) goto out; - rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb, + rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb, lower_buf, rc); out: kfree(lower_buf); - return rc; + return rc ? ERR_PTR(rc) : buf; } static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *buf; - size_t len = PATH_MAX; - int rc; - - rc = ecryptfs_readlink_lower(dentry, &buf, &len); - if (rc) + size_t len; + char *buf = ecryptfs_readlink_lower(dentry, &len); + if (IS_ERR(buf)) goto out; fsstack_copy_attr_atime(dentry->d_inode, ecryptfs_dentry_to_lower(dentry)->d_inode); @@ -1003,10 +998,12 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, char *target; size_t targetsiz; - rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz); - if (!rc) { + target = ecryptfs_readlink_lower(dentry, &targetsiz); + if (!IS_ERR(target)) { kfree(target); stat->size = targetsiz; + } else { + rc = PTR_ERR(target); } } return rc; -- cgit v0.10.2 From 96c8c442117859cd95b5b57836ff374ff43f0564 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 29 Nov 2013 22:54:55 -0500 Subject: xfs: switch to kfree_put_link() don't bother open-coding it... Signed-off-by: Al Viro diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 104455b..a3dad17 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -391,18 +391,6 @@ xfs_vn_follow_link( return NULL; } -STATIC void -xfs_vn_put_link( - struct dentry *dentry, - struct nameidata *nd, - void *p) -{ - char *s = nd_get_link(nd); - - if (!IS_ERR(s)) - kfree(s); -} - STATIC int xfs_vn_getattr( struct vfsmount *mnt, @@ -1118,7 +1106,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { static const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, - .put_link = xfs_vn_put_link, + .put_link = kfree_put_link, .get_acl = xfs_get_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, -- cgit v0.10.2 From 842a859db26b707f06fc9fbbb9137a9b90910e49 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Dec 2013 14:43:54 -0500 Subject: affs: use ->kill_sb() to simplify ->put_super() and failure exits of ->mount() ... and return saner errors from ->mount(), while we are at it Signed-off-by: Al Viro diff --git a/fs/affs/super.c b/fs/affs/super.c index 45161a8..d098731 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -49,11 +49,6 @@ affs_put_super(struct super_block *sb) pr_debug("AFFS: put_super()\n"); cancel_delayed_work_sync(&sbi->sb_work); - kfree(sbi->s_prefix); - affs_free_bitmap(sb); - affs_brelse(sbi->s_root_bh); - kfree(sbi); - sb->s_fs_info = NULL; } static int @@ -316,7 +311,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) unsigned long mount_flags; int tmp_flags; /* fix remount prototype... */ u8 sig[4]; - int ret = -EINVAL; + int ret; save_mount_options(sb, data); @@ -412,17 +407,19 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk(KERN_ERR "AFFS: No valid root block on device %s\n", sb->s_id); - goto out_error; + return -EINVAL; /* N.B. after this point bh must be released */ got_root: + /* Keep super block in cache */ + sbi->s_root_bh = root_bh; root_block = sbi->s_root_block; /* Find out which kind of FS we have */ boot_bh = sb_bread(sb, 0); if (!boot_bh) { printk(KERN_ERR "AFFS: Cannot read boot block\n"); - goto out_error; + return -EINVAL; } memcpy(sig, boot_bh->b_data, 4); brelse(boot_bh); @@ -471,7 +468,7 @@ got_root: default: printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", sb->s_id, chksum); - goto out_error; + return -EINVAL; } if (mount_flags & SF_VERBOSE) { @@ -488,22 +485,17 @@ got_root: if (sbi->s_flags & SF_OFS) sbi->s_data_blksize -= 24; - /* Keep super block in cache */ - sbi->s_root_bh = root_bh; - /* N.B. after this point s_root_bh must be released */ - tmp_flags = sb->s_flags; - if (affs_init_bitmap(sb, &tmp_flags)) - goto out_error; + ret = affs_init_bitmap(sb, &tmp_flags); + if (ret) + return ret; sb->s_flags = tmp_flags; /* set up enough so that it can read an inode */ root_inode = affs_iget(sb, root_block); - if (IS_ERR(root_inode)) { - ret = PTR_ERR(root_inode); - goto out_error; - } + if (IS_ERR(root_inode)) + return PTR_ERR(root_inode); if (AFFS_SB(sb)->s_flags & SF_INTL) sb->s_d_op = &affs_intl_dentry_operations; @@ -513,22 +505,11 @@ got_root: sb->s_root = d_make_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); - goto out_error; + return -ENOMEM; } pr_debug("AFFS: s_flags=%lX\n",sb->s_flags); return 0; - - /* - * Begin the cascaded cleanup ... - */ -out_error: - kfree(sbi->s_bitmap); - affs_brelse(root_bh); - kfree(sbi->s_prefix); - kfree(sbi); - sb->s_fs_info = NULL; - return ret; } static int @@ -615,11 +596,23 @@ static struct dentry *affs_mount(struct file_system_type *fs_type, return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super); } +static void affs_kill_sb(struct super_block *sb) +{ + struct affs_sb_info *sbi = AFFS_SB(sb); + kill_block_super(sb); + if (sbi) { + affs_free_bitmap(sb); + affs_brelse(sbi->s_root_bh); + kfree(sbi->s_prefix); + kfree(sbi); + } +} + static struct file_system_type affs_fs_type = { .owner = THIS_MODULE, .name = "affs", .mount = affs_mount, - .kill_sb = kill_block_super, + .kill_sb = affs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("affs"); -- cgit v0.10.2 From 2309fb8ef40e82c4175100c37eb3d9db9e572ca5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Dec 2013 16:35:14 -0500 Subject: cramfs: get rid of ->put_super() failure exits are simpler that way Signed-off-by: Al Viro diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index e501ac3..508a752 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -219,10 +219,11 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i return read_buffers[buffer] + offset; } -static void cramfs_put_super(struct super_block *sb) +static void cramfs_kill_sb(struct super_block *sb) { - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; + struct cramfs_sb_info *sbi = sb->s_fs_info; + kill_block_super(sb); + kfree(sbi); } static int cramfs_remount(struct super_block *sb, int *flags, char *data) @@ -261,7 +262,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) if (super.magic == CRAMFS_MAGIC_WEND) { if (!silent) printk(KERN_ERR "cramfs: wrong endianness\n"); - goto out; + return -EINVAL; } /* check at 512 byte offset */ @@ -273,20 +274,20 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) printk(KERN_ERR "cramfs: wrong endianness\n"); else if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); - goto out; + return -EINVAL; } } /* get feature flags first */ if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { printk(KERN_ERR "cramfs: unsupported filesystem features\n"); - goto out; + return -EINVAL; } /* Check that the root inode is in a sane state */ if (!S_ISDIR(super.root.mode)) { printk(KERN_ERR "cramfs: root is not a directory\n"); - goto out; + return -EINVAL; } /* correct strange, hard-coded permissions of mkcramfs */ super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); @@ -310,22 +311,18 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) (root_offset != 512 + sizeof(struct cramfs_super)))) { printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset); - goto out; + return -EINVAL; } /* Set it all up.. */ sb->s_op = &cramfs_ops; root = get_cramfs_inode(sb, &super.root, 0); if (IS_ERR(root)) - goto out; + return PTR_ERR(root); sb->s_root = d_make_root(root); if (!sb->s_root) - goto out; + return -ENOMEM; return 0; -out: - kfree(sbi); - sb->s_fs_info = NULL; - return -EINVAL; } static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -550,7 +547,6 @@ static const struct inode_operations cramfs_dir_inode_operations = { }; static const struct super_operations cramfs_ops = { - .put_super = cramfs_put_super, .remount_fs = cramfs_remount, .statfs = cramfs_statfs, }; @@ -565,7 +561,7 @@ static struct file_system_type cramfs_fs_type = { .owner = THIS_MODULE, .name = "cramfs", .mount = cramfs_mount, - .kill_sb = kill_block_super, + .kill_sb = cramfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("cramfs"); -- cgit v0.10.2 From f7f4f4dd6948e3bca0e04e5217c825052ad88f5a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Dec 2013 16:54:28 -0500 Subject: cramfs: take headers to fs/cramfs Signed-off-by: Al Viro diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 3961930..4f424ae 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -17,7 +17,7 @@ #ifdef CONFIG_MTD_UCLINUX #include #include -#include +#include #include #endif diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 1b6ad62..28dd771 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c @@ -24,8 +24,6 @@ #include #include -#include - #include #include diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 508a752..06610cf 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -17,14 +17,30 @@ #include #include #include -#include #include -#include #include #include - +#include #include +#include "internal.h" + +/* + * cramfs super-block data in memory + */ +struct cramfs_sb_info { + unsigned long magic; + unsigned long size; + unsigned long blocks; + unsigned long files; + unsigned long flags; +}; + +static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + static const struct super_operations cramfs_ops; static const struct inode_operations cramfs_dir_inode_operations; static const struct file_operations cramfs_directory_operations; @@ -221,7 +237,7 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i static void cramfs_kill_sb(struct super_block *sb) { - struct cramfs_sb_info *sbi = sb->s_fs_info; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); kill_block_super(sb); kfree(sbi); } diff --git a/fs/cramfs/internal.h b/fs/cramfs/internal.h new file mode 100644 index 0000000..349d712 --- /dev/null +++ b/fs/cramfs/internal.h @@ -0,0 +1,4 @@ +/* Uncompression interfaces to the underlying zlib */ +int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); +int cramfs_uncompress_init(void); +void cramfs_uncompress_exit(void); diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index 0233298..1760c1b 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include "internal.h" static z_stream stream; static int initialized; diff --git a/include/linux/cramfs_fs.h b/include/linux/cramfs_fs.h deleted file mode 100644 index 1337896..0000000 --- a/include/linux/cramfs_fs.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __CRAMFS_H -#define __CRAMFS_H - -#include - -/* Uncompression interfaces to the underlying zlib */ -int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); -int cramfs_uncompress_init(void); -void cramfs_uncompress_exit(void); -#endif diff --git a/include/linux/cramfs_fs_sb.h b/include/linux/cramfs_fs_sb.h deleted file mode 100644 index 8390693..0000000 --- a/include/linux/cramfs_fs_sb.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _CRAMFS_FS_SB -#define _CRAMFS_FS_SB - -/* - * cramfs super-block data in memory - */ -struct cramfs_sb_info { - unsigned long magic; - unsigned long size; - unsigned long blocks; - unsigned long files; - unsigned long flags; -}; - -static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -#endif diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 7c098ac..a822702 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v0.10.2 From 5a9ed6f5e7b80c95b133818aa96b1fba8e1216a0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Dec 2013 17:05:05 -0500 Subject: efs: get rid of ->put_super() simplifies failure exits in ->mount()... Signed-off-by: Al Viro diff --git a/fs/efs/super.c b/fs/efs/super.c index c6f57a7..50215bb 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -26,11 +26,18 @@ static struct dentry *efs_mount(struct file_system_type *fs_type, return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super); } +static void efs_kill_sb(struct super_block *s) +{ + struct efs_sb_info *sbi = SUPER_INFO(s); + kill_block_super(s); + kfree(sbi); +} + static struct file_system_type efs_fs_type = { .owner = THIS_MODULE, .name = "efs", .mount = efs_mount, - .kill_sb = kill_block_super, + .kill_sb = efs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("efs"); @@ -105,12 +112,6 @@ static void destroy_inodecache(void) kmem_cache_destroy(efs_inode_cachep); } -static void efs_put_super(struct super_block *s) -{ - kfree(s->s_fs_info); - s->s_fs_info = NULL; -} - static int efs_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_RDONLY; @@ -120,7 +121,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data) static const struct super_operations efs_superblock_operations = { .alloc_inode = efs_alloc_inode, .destroy_inode = efs_destroy_inode, - .put_super = efs_put_super, .statfs = efs_statfs, .remount_fs = efs_remount, }; @@ -259,7 +259,6 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) struct efs_sb_info *sb; struct buffer_head *bh; struct inode *root; - int ret = -EINVAL; sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL); if (!sb) @@ -270,7 +269,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) { printk(KERN_ERR "EFS: device does not support %d byte blocks\n", EFS_BLOCKSIZE); - goto out_no_fs_ul; + return -EINVAL; } /* read the vh (volume header) block */ @@ -278,7 +277,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) if (!bh) { printk(KERN_ERR "EFS: cannot read volume header\n"); - goto out_no_fs_ul; + return -EINVAL; } /* @@ -290,13 +289,13 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) brelse(bh); if (sb->fs_start == -1) { - goto out_no_fs_ul; + return -EINVAL; } bh = sb_bread(s, sb->fs_start + EFS_SUPER); if (!bh) { printk(KERN_ERR "EFS: cannot read superblock\n"); - goto out_no_fs_ul; + return -EINVAL; } if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) { @@ -304,7 +303,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) printk(KERN_WARNING "EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER); #endif brelse(bh); - goto out_no_fs_ul; + return -EINVAL; } brelse(bh); @@ -319,24 +318,16 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) root = efs_iget(s, EFS_ROOTINODE); if (IS_ERR(root)) { printk(KERN_ERR "EFS: get root inode failed\n"); - ret = PTR_ERR(root); - goto out_no_fs; + return PTR_ERR(root); } s->s_root = d_make_root(root); if (!(s->s_root)) { printk(KERN_ERR "EFS: get root dentry failed\n"); - ret = -ENOMEM; - goto out_no_fs; + return -ENOMEM; } return 0; - -out_no_fs_ul: -out_no_fs: - s->s_fs_info = NULL; - kfree(sb); - return ret; } static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) { -- cgit v0.10.2 From 208adb6403e079ceeb8e731696615d22db6f397b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Dec 2013 19:48:58 -0500 Subject: qnx4: clean qnx4_fill_super() up * pass on-disk superblock to qnx4_chkroot() explicitly * don't leave stale (and unused) pointers in qnx4_super_block * free stuff in ->kill_sb(); ->put_super() becomes empty and dies * simplify failure exits Signed-off-by: Al Viro diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 2e8caa6..89558810 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -27,7 +27,6 @@ static const struct super_operations qnx4_sops; -static void qnx4_put_super(struct super_block *sb); static struct inode *qnx4_alloc_inode(struct super_block *sb); static void qnx4_destroy_inode(struct inode *inode); static int qnx4_remount(struct super_block *sb, int *flags, char *data); @@ -37,7 +36,6 @@ static const struct super_operations qnx4_sops = { .alloc_inode = qnx4_alloc_inode, .destroy_inode = qnx4_destroy_inode, - .put_super = qnx4_put_super, .statfs = qnx4_statfs, .remount_fs = qnx4_remount, }; @@ -148,18 +146,19 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf) * it really _is_ a qnx4 filesystem, and to check the size * of the directory entry. */ -static const char *qnx4_checkroot(struct super_block *sb) +static const char *qnx4_checkroot(struct super_block *sb, + struct qnx4_super_block *s) { struct buffer_head *bh; struct qnx4_inode_entry *rootdir; int rd, rl; int i, j; - if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') + if (s->RootDir.di_fname[0] != '/' || s->RootDir.di_fname[1] != '\0') return "no qnx4 filesystem (no root dir)."; QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); - rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; - rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); + rd = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_blk) - 1; + rl = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { bh = sb_bread(sb, rd + j); /* root dir, first block */ if (bh == NULL) @@ -189,7 +188,6 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) struct inode *root; const char *errmsg; struct qnx4_sb_info *qs; - int ret = -EINVAL; qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL); if (!qs) @@ -198,67 +196,50 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) sb_set_blocksize(s, QNX4_BLOCK_SIZE); + s->s_op = &qnx4_sops; + s->s_magic = QNX4_SUPER_MAGIC; + s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ + /* Check the superblock signature. Since the qnx4 code is dangerous, we should leave as quickly as possible if we don't belong here... */ bh = sb_bread(s, 1); if (!bh) { printk(KERN_ERR "qnx4: unable to read the superblock\n"); - goto outnobh; + return -EINVAL; } - if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { - if (!silent) - printk(KERN_ERR "qnx4: wrong fsid in superblock.\n"); - goto out; - } - s->s_op = &qnx4_sops; - s->s_magic = QNX4_SUPER_MAGIC; - s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ - qnx4_sb(s)->sb_buf = bh; - qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data; - /* check before allocating dentries, inodes, .. */ - errmsg = qnx4_checkroot(s); + errmsg = qnx4_checkroot(s, (struct qnx4_super_block *) bh->b_data); + brelse(bh); if (errmsg != NULL) { if (!silent) printk(KERN_ERR "qnx4: %s\n", errmsg); - goto out; + return -EINVAL; } /* does root not have inode number QNX4_ROOT_INO ?? */ root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); if (IS_ERR(root)) { printk(KERN_ERR "qnx4: get inode failed\n"); - ret = PTR_ERR(root); - goto outb; + return PTR_ERR(root); } - ret = -ENOMEM; s->s_root = d_make_root(root); if (s->s_root == NULL) - goto outb; + return -ENOMEM; - brelse(bh); return 0; - - outb: - kfree(qs->BitMap); - out: - brelse(bh); - outnobh: - kfree(qs); - s->s_fs_info = NULL; - return ret; } -static void qnx4_put_super(struct super_block *sb) +static void qnx4_kill_sb(struct super_block *sb) { struct qnx4_sb_info *qs = qnx4_sb(sb); - kfree( qs->BitMap ); - kfree( qs ); - sb->s_fs_info = NULL; - return; + kill_block_super(sb); + if (qs) { + kfree(qs->BitMap); + kfree(qs); + } } static int qnx4_readpage(struct file *file, struct page *page) @@ -409,7 +390,7 @@ static struct file_system_type qnx4_fs_type = { .owner = THIS_MODULE, .name = "qnx4", .mount = qnx4_mount, - .kill_sb = kill_block_super, + .kill_sb = qnx4_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("qnx4"); diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h index 34e2d32..c9b1be2 100644 --- a/fs/qnx4/qnx4.h +++ b/fs/qnx4/qnx4.h @@ -10,8 +10,6 @@ #endif struct qnx4_sb_info { - struct buffer_head *sb_buf; /* superblock buffer */ - struct qnx4_super_block *sb; /* our superblock */ unsigned int Version; /* may be useful */ struct qnx4_inode_entry *BitMap; /* useful */ }; -- cgit v0.10.2 From 1c1c8747cd0528fe1d225badf25bf5346d799ea3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Dec 2013 23:07:51 -0500 Subject: btrfs: sanitize BTRFS_IOC_FILE_EXTENT_SAME * don't assume that ->dest_count won't change between copy_from_user() and memdup_user() * use fdget instead of fget * don't bother comparing superblocks when we'd already compared vfsmounts * get rid of excessive goto * use file_inode() instead of open-coding the sucker Signed-off-by: Al Viro diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 21da576..ad27dce 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2686,14 +2686,11 @@ out_unlock: #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) static long btrfs_ioctl_file_extent_same(struct file *file, - void __user *argp) + struct btrfs_ioctl_same_args __user *argp) { - struct btrfs_ioctl_same_args tmp; struct btrfs_ioctl_same_args *same; struct btrfs_ioctl_same_extent_info *info; - struct inode *src = file->f_dentry->d_inode; - struct file *dst_file = NULL; - struct inode *dst; + struct inode *src = file_inode(file); u64 off; u64 len; int i; @@ -2701,6 +2698,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, unsigned long size; u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; bool is_admin = capable(CAP_SYS_ADMIN); + u16 count; if (!(file->f_mode & FMODE_READ)) return -EINVAL; @@ -2709,17 +2707,14 @@ static long btrfs_ioctl_file_extent_same(struct file *file, if (ret) return ret; - if (copy_from_user(&tmp, - (struct btrfs_ioctl_same_args __user *)argp, - sizeof(tmp))) { + if (get_user(count, &argp->dest_count)) { ret = -EFAULT; goto out; } - size = sizeof(tmp) + - tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info); + size = offsetof(struct btrfs_ioctl_same_args __user, info[count]); - same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size); + same = memdup_user(argp, size); if (IS_ERR(same)) { ret = PTR_ERR(same); @@ -2756,52 +2751,35 @@ static long btrfs_ioctl_file_extent_same(struct file *file, goto out; /* pre-format output fields to sane values */ - for (i = 0; i < same->dest_count; i++) { + for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; same->info[i].status = 0; } - ret = 0; - for (i = 0; i < same->dest_count; i++) { - info = &same->info[i]; - - dst_file = fget(info->fd); - if (!dst_file) { + for (i = 0, info = same->info; i < count; i++, info++) { + struct inode *dst; + struct fd dst_file = fdget(info->fd); + if (!dst_file.file) { info->status = -EBADF; - goto next; + continue; } + dst = file_inode(dst_file.file); - if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { + if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) { info->status = -EINVAL; - goto next; - } - - info->status = -EXDEV; - if (file->f_path.mnt != dst_file->f_path.mnt) - goto next; - - dst = dst_file->f_dentry->d_inode; - if (src->i_sb != dst->i_sb) - goto next; - - if (S_ISDIR(dst->i_mode)) { + } else if (file->f_path.mnt != dst_file.file->f_path.mnt) { + info->status = -EXDEV; + } else if (S_ISDIR(dst->i_mode)) { info->status = -EISDIR; - goto next; - } - - if (!S_ISREG(dst->i_mode)) { + } else if (!S_ISREG(dst->i_mode)) { info->status = -EACCES; - goto next; + } else { + info->status = btrfs_extent_same(src, off, len, dst, + info->logical_offset); + if (info->status == 0) + info->bytes_deduped += len; } - - info->status = btrfs_extent_same(src, off, len, dst, - info->logical_offset); - if (info->status == 0) - info->bytes_deduped += len; - -next: - if (dst_file) - fput(dst_file); + fdput(dst_file); } ret = copy_to_user(argp, same, size); -- cgit v0.10.2 From 36a7411724b1caf2fa92b5e4a41576ee8f16769e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 23 Dec 2013 16:51:33 -0500 Subject: eventfd_ctx_fdget(): use fdget() instead of fget() Signed-off-by: Al Viro diff --git a/fs/eventfd.c b/fs/eventfd.c index 35470d9..d6a88e7 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -349,15 +349,12 @@ EXPORT_SYMBOL_GPL(eventfd_fget); */ struct eventfd_ctx *eventfd_ctx_fdget(int fd) { - struct file *file; struct eventfd_ctx *ctx; - - file = eventfd_fget(fd); - if (IS_ERR(file)) - return (struct eventfd_ctx *) file; - ctx = eventfd_ctx_get(file->private_data); - fput(file); - + struct fd f = fdget(fd); + if (!f.file) + return ERR_PTR(-EBADF); + ctx = eventfd_ctx_fileget(f.file); + fdput(f); return ctx; } EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); -- cgit v0.10.2 From 479e64c21038326f4fe429b4ffb7ea6d3175c2dc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 22 Nov 2013 01:45:04 -0500 Subject: nls: have register_nls() set ->owner pass owner explicitly to __register_nls(), make register_nls() a macro passing THIS_MODULE as the owner argument to __register_nls(). Signed-off-by: Al Viro diff --git a/fs/nls/mac-celtic.c b/fs/nls/mac-celtic.c index 634a8b7..266c2d7 100644 --- a/fs/nls/mac-celtic.c +++ b/fs/nls/mac-celtic.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macceltic(void) diff --git a/fs/nls/mac-centeuro.c b/fs/nls/mac-centeuro.c index 979e626..9789c60 100644 --- a/fs/nls/mac-centeuro.c +++ b/fs/nls/mac-centeuro.c @@ -513,7 +513,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccenteuro(void) diff --git a/fs/nls/mac-croatian.c b/fs/nls/mac-croatian.c index dd3f675..bb19e7a 100644 --- a/fs/nls/mac-croatian.c +++ b/fs/nls/mac-croatian.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccroatian(void) diff --git a/fs/nls/mac-cyrillic.c b/fs/nls/mac-cyrillic.c index 1112c84..2a7dea3 100644 --- a/fs/nls/mac-cyrillic.c +++ b/fs/nls/mac-cyrillic.c @@ -478,7 +478,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccyrillic(void) diff --git a/fs/nls/mac-gaelic.c b/fs/nls/mac-gaelic.c index 2de9158..77b0016 100644 --- a/fs/nls/mac-gaelic.c +++ b/fs/nls/mac-gaelic.c @@ -548,7 +548,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macgaelic(void) diff --git a/fs/nls/mac-greek.c b/fs/nls/mac-greek.c index a863100..1eccf499 100644 --- a/fs/nls/mac-greek.c +++ b/fs/nls/mac-greek.c @@ -478,7 +478,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macgreek(void) diff --git a/fs/nls/mac-iceland.c b/fs/nls/mac-iceland.c index babe299..cbd0875 100644 --- a/fs/nls/mac-iceland.c +++ b/fs/nls/mac-iceland.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maciceland(void) diff --git a/fs/nls/mac-inuit.c b/fs/nls/mac-inuit.c index 312364f..fba8357 100644 --- a/fs/nls/mac-inuit.c +++ b/fs/nls/mac-inuit.c @@ -513,7 +513,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macinuit(void) diff --git a/fs/nls/mac-roman.c b/fs/nls/mac-roman.c index 53ce080..b6a98a5 100644 --- a/fs/nls/mac-roman.c +++ b/fs/nls/mac-roman.c @@ -618,7 +618,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macroman(void) diff --git a/fs/nls/mac-romanian.c b/fs/nls/mac-romanian.c index add6f7a..25547f0 100644 --- a/fs/nls/mac-romanian.c +++ b/fs/nls/mac-romanian.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macromanian(void) diff --git a/fs/nls/mac-turkish.c b/fs/nls/mac-turkish.c index dffa96d..b5454bc 100644 --- a/fs/nls/mac-turkish.c +++ b/fs/nls/mac-turkish.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macturkish(void) diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c index 7020e94..a262065 100644 --- a/fs/nls/nls_ascii.c +++ b/fs/nls/nls_ascii.c @@ -148,7 +148,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_ascii(void) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index fea6bd5..52ccd34 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -232,13 +232,14 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, } EXPORT_SYMBOL(utf16s_to_utf8s); -int register_nls(struct nls_table * nls) +int __register_nls(struct nls_table *nls, struct module *owner) { struct nls_table ** tmp = &tables; if (nls->next) return -EBUSY; + nls->owner = owner; spin_lock(&nls_lock); while (*tmp) { if (nls == *tmp) { @@ -252,6 +253,7 @@ int register_nls(struct nls_table * nls) spin_unlock(&nls_lock); return 0; } +EXPORT_SYMBOL(__register_nls); int unregister_nls(struct nls_table * nls) { @@ -538,7 +540,6 @@ struct nls_table *load_nls_default(void) return &default_table; } -EXPORT_SYMBOL(register_nls); EXPORT_SYMBOL(unregister_nls); EXPORT_SYMBOL(unload_nls); EXPORT_SYMBOL(load_nls); diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c index c8471fe..ace3e19 100644 --- a/fs/nls/nls_cp1250.c +++ b/fs/nls/nls_cp1250.c @@ -329,7 +329,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1250(void) diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c index 1939b46..9273ddf 100644 --- a/fs/nls/nls_cp1251.c +++ b/fs/nls/nls_cp1251.c @@ -283,7 +283,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1251(void) diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c index 8120ae2..1caf5df 100644 --- a/fs/nls/nls_cp1255.c +++ b/fs/nls/nls_cp1255.c @@ -365,7 +365,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1255(void) diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c index ff37a462..7ddb830 100644 --- a/fs/nls/nls_cp437.c +++ b/fs/nls/nls_cp437.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp437(void) diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c index f5576b8..c593f68 100644 --- a/fs/nls/nls_cp737.c +++ b/fs/nls/nls_cp737.c @@ -332,7 +332,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp737(void) diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c index 4905635..554c863 100644 --- a/fs/nls/nls_cp775.c +++ b/fs/nls/nls_cp775.c @@ -301,7 +301,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp775(void) diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c index fe5bdad..56cccd1 100644 --- a/fs/nls/nls_cp850.c +++ b/fs/nls/nls_cp850.c @@ -297,7 +297,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp850(void) diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c index ceb1c01..7cdc05a 100644 --- a/fs/nls/nls_cp852.c +++ b/fs/nls/nls_cp852.c @@ -319,7 +319,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp852(void) diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c index cc7f5fb2..7426eea 100644 --- a/fs/nls/nls_cp855.c +++ b/fs/nls/nls_cp855.c @@ -281,7 +281,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp855(void) diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c index e418e19..0983097 100644 --- a/fs/nls/nls_cp857.c +++ b/fs/nls/nls_cp857.c @@ -283,7 +283,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp857(void) diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c index a86c97d..8422447 100644 --- a/fs/nls/nls_cp860.c +++ b/fs/nls/nls_cp860.c @@ -346,7 +346,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp860(void) diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c index bd92022..dc873e4 100644 --- a/fs/nls/nls_cp861.c +++ b/fs/nls/nls_cp861.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp861(void) diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c index e9b68eb..d5263e3 100644 --- a/fs/nls/nls_cp862.c +++ b/fs/nls/nls_cp862.c @@ -403,7 +403,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp862(void) diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c index f8a9b07..051c983 100644 --- a/fs/nls/nls_cp863.c +++ b/fs/nls/nls_cp863.c @@ -363,7 +363,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp863(void) diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c index 8d31f43..97eb127 100644 --- a/fs/nls/nls_cp864.c +++ b/fs/nls/nls_cp864.c @@ -389,7 +389,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp864(void) diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c index 4bd902f..1112142 100644 --- a/fs/nls/nls_cp865.c +++ b/fs/nls/nls_cp865.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp865(void) diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c index bdc7cb3..ffdcbc3 100644 --- a/fs/nls/nls_cp866.c +++ b/fs/nls/nls_cp866.c @@ -287,7 +287,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp866(void) diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c index 9f283a2..3b5a345 100644 --- a/fs/nls/nls_cp869.c +++ b/fs/nls/nls_cp869.c @@ -297,7 +297,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp869(void) diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c index 0b3c488..8dfaa10 100644 --- a/fs/nls/nls_cp874.c +++ b/fs/nls/nls_cp874.c @@ -256,7 +256,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp874(void) diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c index 0ffed6f..67b7398 100644 --- a/fs/nls/nls_cp932.c +++ b/fs/nls/nls_cp932.c @@ -7914,7 +7914,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp932(void) diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c index 8277030..c96546c 100644 --- a/fs/nls/nls_cp936.c +++ b/fs/nls/nls_cp936.c @@ -11092,7 +11092,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp936(void) diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c index 8a7a2fe..199171e 100644 --- a/fs/nls/nls_cp949.c +++ b/fs/nls/nls_cp949.c @@ -13927,7 +13927,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp949(void) diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c index ef25368..8e14187 100644 --- a/fs/nls/nls_cp950.c +++ b/fs/nls/nls_cp950.c @@ -9463,7 +9463,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp950(void) diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 7424929..162b3f1 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -553,7 +553,6 @@ static struct nls_table table = { .charset = "euc-jp", .uni2char = uni2char, .char2uni = char2uni, - .owner = THIS_MODULE, }; static int __init init_nls_euc_jp(void) diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c index 7b951bb..69ac020 100644 --- a/fs/nls/nls_iso8859-1.c +++ b/fs/nls/nls_iso8859-1.c @@ -239,7 +239,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_1(void) diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c index c4d52ea..afb3f8f 100644 --- a/fs/nls/nls_iso8859-13.c +++ b/fs/nls/nls_iso8859-13.c @@ -267,7 +267,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_13(void) diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c index dc02600..046370f 100644 --- a/fs/nls/nls_iso8859-14.c +++ b/fs/nls/nls_iso8859-14.c @@ -323,7 +323,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_14(void) diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c index 3c7dfc8..7e34a84 100644 --- a/fs/nls/nls_iso8859-15.c +++ b/fs/nls/nls_iso8859-15.c @@ -289,7 +289,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_15(void) diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c index a2d2197..7dd5711 100644 --- a/fs/nls/nls_iso8859-2.c +++ b/fs/nls/nls_iso8859-2.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_2(void) diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c index a61e0da..740b75e 100644 --- a/fs/nls/nls_iso8859-3.c +++ b/fs/nls/nls_iso8859-3.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_3(void) diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c index e8ff555..8826021 100644 --- a/fs/nls/nls_iso8859-4.c +++ b/fs/nls/nls_iso8859-4.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_4(void) diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c index 4721e89..7c04057 100644 --- a/fs/nls/nls_iso8859-5.c +++ b/fs/nls/nls_iso8859-5.c @@ -254,7 +254,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_5(void) diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c index 01a517d..d4a8814 100644 --- a/fs/nls/nls_iso8859-6.c +++ b/fs/nls/nls_iso8859-6.c @@ -245,7 +245,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_6(void) diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c index 2d27b93..37b75d8 100644 --- a/fs/nls/nls_iso8859-7.c +++ b/fs/nls/nls_iso8859-7.c @@ -299,7 +299,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_7(void) diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c index 694bf07..557b982 100644 --- a/fs/nls/nls_iso8859-9.c +++ b/fs/nls/nls_iso8859-9.c @@ -254,7 +254,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_9(void) diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c index 4387531..811f232 100644 --- a/fs/nls/nls_koi8-r.c +++ b/fs/nls/nls_koi8-r.c @@ -305,7 +305,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_r(void) diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c index e7bc1d7..a80a741 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -55,7 +55,6 @@ static struct nls_table table = { .charset = "koi8-ru", .uni2char = uni2char, .char2uni = char2uni, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_ru(void) diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c index 8c9f029..7e029e4 100644 --- a/fs/nls/nls_koi8-u.c +++ b/fs/nls/nls_koi8-u.c @@ -312,7 +312,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_u(void) diff --git a/fs/nls/nls_utf8.c b/fs/nls/nls_utf8.c index 0d60a44..afcfbc4 100644 --- a/fs/nls/nls_utf8.c +++ b/fs/nls/nls_utf8.c @@ -46,7 +46,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = identity, /* no conversion */ .charset2upper = identity, - .owner = THIS_MODULE, }; static int __init init_nls_utf8(void) diff --git a/include/linux/nls.h b/include/linux/nls.h index 5dc635f..520681b 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h @@ -44,11 +44,12 @@ enum utf16_endian { }; /* nls_base.c */ -extern int register_nls(struct nls_table *); +extern int __register_nls(struct nls_table *, struct module *); extern int unregister_nls(struct nls_table *); extern struct nls_table *load_nls(char *); extern void unload_nls(struct nls_table *); extern struct nls_table *load_nls_default(void); +#define register_nls(nls) __register_nls((nls), THIS_MODULE) extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu); extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen); -- cgit v0.10.2 From b42d570c9fbebc8e779fbcbc2b598fa94a0e809f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 22 Nov 2013 01:53:47 -0500 Subject: afs: get rid of junk in fs/afs/proc.c kill pointless method instances and don't bother with ->owner - it's ignored for procfs files anyway, make use of remove_proc_subtree() for removal, get rid of cell->proc_dir. Signed-off-by: Al Viro diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a306bb6..6621f80 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -195,7 +195,6 @@ struct afs_cell { struct list_head link; /* main cell list link */ struct key *anonymous_key; /* anonymous user key for this cell */ struct list_head proc_link; /* /proc cell list link */ - struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ #ifdef CONFIG_AFS_FSCACHE struct fscache_cookie *cache; /* caching cookie */ #endif diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 526e4bb..bddc512 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -41,11 +41,8 @@ static const struct file_operations afs_proc_cells_fops = { .write = afs_proc_cells_write, .llseek = seq_lseek, .release = seq_release, - .owner = THIS_MODULE, }; -static int afs_proc_rootcell_open(struct inode *inode, struct file *file); -static int afs_proc_rootcell_release(struct inode *inode, struct file *file); static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, size_t size, loff_t *_pos); static ssize_t afs_proc_rootcell_write(struct file *file, @@ -53,17 +50,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file, size_t size, loff_t *_pos); static const struct file_operations afs_proc_rootcell_fops = { - .open = afs_proc_rootcell_open, .read = afs_proc_rootcell_read, .write = afs_proc_rootcell_write, .llseek = no_llseek, - .release = afs_proc_rootcell_release, - .owner = THIS_MODULE, }; static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); -static int afs_proc_cell_volumes_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *pos); @@ -81,14 +73,11 @@ static const struct file_operations afs_proc_cell_volumes_fops = { .open = afs_proc_cell_volumes_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_volumes_release, - .owner = THIS_MODULE, + .release = seq_release, }; static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file); -static int afs_proc_cell_vlservers_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *pos); @@ -106,13 +95,10 @@ static const struct file_operations afs_proc_cell_vlservers_fops = { .open = afs_proc_cell_vlservers_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_vlservers_release, - .owner = THIS_MODULE, + .release = seq_release, }; static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); -static int afs_proc_cell_servers_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *pos); @@ -130,8 +116,7 @@ static const struct file_operations afs_proc_cell_servers_fops = { .open = afs_proc_cell_servers_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_servers_release, - .owner = THIS_MODULE, + .release = seq_release, }; /* @@ -139,29 +124,21 @@ static const struct file_operations afs_proc_cell_servers_fops = { */ int afs_proc_init(void) { - struct proc_dir_entry *p; - _enter(""); proc_afs = proc_mkdir("fs/afs", NULL); if (!proc_afs) goto error_dir; - p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops); - if (!p) - goto error_cells; - - p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops); - if (!p) - goto error_rootcell; + if (!proc_create("cells", 0, proc_afs, &afs_proc_cells_fops) || + !proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops)) + goto error_tree; _leave(" = 0"); return 0; -error_rootcell: - remove_proc_entry("cells", proc_afs); -error_cells: - remove_proc_entry("fs/afs", NULL); +error_tree: + remove_proc_subtree("fs/afs", NULL); error_dir: _leave(" = -ENOMEM"); return -ENOMEM; @@ -172,9 +149,7 @@ error_dir: */ void afs_proc_cleanup(void) { - remove_proc_entry("rootcell", proc_afs); - remove_proc_entry("cells", proc_afs); - remove_proc_entry("fs/afs", NULL); + remove_proc_subtree("fs/afs", NULL); } /* @@ -319,19 +294,6 @@ inval: goto done; } -/* - * Stubs for /proc/fs/afs/rootcell - */ -static int afs_proc_rootcell_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int afs_proc_rootcell_release(struct inode *inode, struct file *file) -{ - return 0; -} - static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, size_t size, loff_t *_pos) { @@ -387,38 +349,27 @@ nomem: */ int afs_proc_cell_setup(struct afs_cell *cell) { - struct proc_dir_entry *p; + struct proc_dir_entry *dir; _enter("%p{%s}", cell, cell->name); - cell->proc_dir = proc_mkdir(cell->name, proc_afs); - if (!cell->proc_dir) + dir = proc_mkdir(cell->name, proc_afs); + if (!dir) goto error_dir; - p = proc_create_data("servers", 0, cell->proc_dir, - &afs_proc_cell_servers_fops, cell); - if (!p) - goto error_servers; - - p = proc_create_data("vlservers", 0, cell->proc_dir, - &afs_proc_cell_vlservers_fops, cell); - if (!p) - goto error_vlservers; - - p = proc_create_data("volumes", 0, cell->proc_dir, - &afs_proc_cell_volumes_fops, cell); - if (!p) - goto error_volumes; + if (!proc_create_data("servers", 0, dir, + &afs_proc_cell_servers_fops, cell) || + !proc_create_data("vlservers", 0, dir, + &afs_proc_cell_vlservers_fops, cell) || + !proc_create_data("volumes", 0, dir, + &afs_proc_cell_volumes_fops, cell)) + goto error_tree; _leave(" = 0"); return 0; -error_volumes: - remove_proc_entry("vlservers", cell->proc_dir); -error_vlservers: - remove_proc_entry("servers", cell->proc_dir); -error_servers: - remove_proc_entry(cell->name, proc_afs); +error_tree: + remove_proc_subtree(cell->name, proc_afs); error_dir: _leave(" = -ENOMEM"); return -ENOMEM; @@ -431,10 +382,7 @@ void afs_proc_cell_remove(struct afs_cell *cell) { _enter(""); - remove_proc_entry("volumes", cell->proc_dir); - remove_proc_entry("vlservers", cell->proc_dir); - remove_proc_entry("servers", cell->proc_dir); - remove_proc_entry(cell->name, proc_afs); + remove_proc_subtree(cell->name, proc_afs); _leave(""); } @@ -463,14 +411,6 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ @@ -569,15 +509,6 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_vlservers_release(struct inode *inode, - struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ @@ -673,15 +604,6 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_servers_release(struct inode *inode, - struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ -- cgit v0.10.2 From 2ccdc413196b43a02bb68b46be5b68850904e9ea Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 22 Nov 2013 13:25:39 -0500 Subject: kill reiserfs_bdevname() it's never called with NULL argument... Signed-off-by: Al Viro diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index a958444..02b0b7d 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -419,7 +419,7 @@ int reiserfs_proc_info_init(struct super_block *sb) char *s; /* Some block devices use /'s */ - strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE); + strlcpy(b, sb->s_id, BDEVNAME_SIZE); s = strchr(b, '/'); if (s) *s = '!'; @@ -449,7 +449,7 @@ int reiserfs_proc_info_done(struct super_block *sb) char *s; /* Some block devices use /'s */ - strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE); + strlcpy(b, sb->s_id, BDEVNAME_SIZE); s = strchr(b, '/'); if (s) *s = '!'; diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index f8adaee..24f068c 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -608,14 +608,6 @@ int reiserfs_resize(struct super_block *, unsigned long); #define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->) -/* A safe version of the "bdevname", which returns the "s_id" field of - * a superblock or else "Null superblock" if the super block is NULL. - */ -static inline char *reiserfs_bdevname(struct super_block *s) -{ - return (s == NULL) ? "Null superblock" : s->s_id; -} - #define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal))) static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal *journal) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 3ead145..2c80335 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1479,7 +1479,7 @@ static int read_super_block(struct super_block *s, int offset) if (!bh) { reiserfs_warning(s, "sh-2006", "bread failed (dev %s, block %lu, size %lu)", - reiserfs_bdevname(s), offset / s->s_blocksize, + s->s_id, offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -1500,7 +1500,7 @@ static int read_super_block(struct super_block *s, int offset) if (!bh) { reiserfs_warning(s, "sh-2007", "bread failed (dev %s, block %lu, size %lu)", - reiserfs_bdevname(s), offset / s->s_blocksize, + s->s_id, offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -1509,7 +1509,7 @@ static int read_super_block(struct super_block *s, int offset) if (sb_blocksize(rs) != s->s_blocksize) { reiserfs_warning(s, "sh-2011", "can't find a reiserfs " "filesystem on (dev %s, block %Lu, size %lu)", - reiserfs_bdevname(s), + s->s_id, (unsigned long long)bh->b_blocknr, s->s_blocksize); brelse(bh); @@ -1825,7 +1825,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) /* try new format (64-th 1k block), which can contain reiserfs super block */ else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) { SWARN(silent, s, "sh-2021", "can not find reiserfs on %s", - reiserfs_bdevname(s)); + s->s_id); goto error_unlocked; } -- cgit v0.10.2 From a8d4b8345e0ee48b732126d980efaf0dc373e2b0 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 11 Jan 2014 19:19:32 +0100 Subject: introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() rcu_dereference_check_fdtable() looks very wrong, 1. rcu_my_thread_group_empty() was added by 844b9a8707f1 "vfs: fix RCU-lockdep false positive due to /proc" but it doesn't really fix the problem. A CLONE_THREAD (without CLONE_FILES) task can hit the same race with get_files_struct(). And otoh rcu_my_thread_group_empty() can suppress the correct warning if the caller is the CLONE_FILES (without CLONE_THREAD) task. 2. files->count == 1 check is not really right too. Even if this files_struct is not shared it is not safe to access it lockless unless the caller is the owner. Otoh, this check is sub-optimal. files->count == 0 always means it is safe to use it lockless even if files != current->files, but put_files_struct() has to take rcu_read_lock(). See the next patch. This patch removes the buggy checks and turns fcheck_files() into __fcheck_files() which uses rcu_dereference_raw(), the "unshared" callers, fget_light() and fget_raw_light(), can use it to avoid the warning from RCU-lockdep. fcheck_files() is trivially reimplemented as rcu_lockdep_assert() plus __fcheck_files(). Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/file.c b/fs/file.c index 4a78f98..957cbc0 100644 --- a/fs/file.c +++ b/fs/file.c @@ -707,7 +707,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed) *fput_needed = 0; if (atomic_read(&files->count) == 1) { - file = fcheck_files(files, fd); + file = __fcheck_files(files, fd); if (file && (file->f_mode & FMODE_PATH)) file = NULL; } else { @@ -735,7 +735,7 @@ struct file *fget_raw_light(unsigned int fd, int *fput_needed) *fput_needed = 0; if (atomic_read(&files->count) == 1) { - file = fcheck_files(files, fd); + file = __fcheck_files(files, fd); } else { rcu_read_lock(); file = fcheck_files(files, fd); diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 085197b..70e8e21 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -59,29 +59,36 @@ struct files_struct { struct file __rcu * fd_array[NR_OPEN_DEFAULT]; }; -#define rcu_dereference_check_fdtable(files, fdtfd) \ - (rcu_dereference_check((fdtfd), \ - lockdep_is_held(&(files)->file_lock) || \ - atomic_read(&(files)->count) == 1 || \ - rcu_my_thread_group_empty())) - -#define files_fdtable(files) \ - (rcu_dereference_check_fdtable((files), (files)->fdt)) - struct file_operations; struct vfsmount; struct dentry; extern void __init files_defer_init(void); -static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) +#define rcu_dereference_check_fdtable(files, fdtfd) \ + rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock)) + +#define files_fdtable(files) \ + rcu_dereference_check_fdtable((files), (files)->fdt) + +/* + * The caller must ensure that fd table isn't shared or hold rcu or file lock + */ +static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd) { - struct file * file = NULL; - struct fdtable *fdt = files_fdtable(files); + struct fdtable *fdt = rcu_dereference_raw(files->fdt); if (fd < fdt->max_fds) - file = rcu_dereference_check_fdtable(files, fdt->fd[fd]); - return file; + return rcu_dereference_raw(fdt->fd[fd]); + return NULL; +} + +static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) +{ + rcu_lockdep_assert(rcu_read_lock_held() || + lockdep_is_held(&files->file_lock), + "suspicious rcu_dereference_check() usage"); + return __fcheck_files(files, fd); } /* diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 39cbb88..a2482cf 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -448,8 +448,6 @@ static inline int rcu_read_lock_sched_held(void) #ifdef CONFIG_PROVE_RCU -extern int rcu_my_thread_group_empty(void); - /** * rcu_lockdep_assert - emit lockdep splat if specified condition not met * @c: condition to check diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 6cb3dff..a3596c8 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -195,17 +195,6 @@ void wait_rcu_gp(call_rcu_func_t crf) } EXPORT_SYMBOL_GPL(wait_rcu_gp); -#ifdef CONFIG_PROVE_RCU -/* - * wrapper function to avoid #include problems. - */ -int rcu_my_thread_group_empty(void) -{ - return thread_group_empty(current); -} -EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty); -#endif /* #ifdef CONFIG_PROVE_RCU */ - #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD static inline void debug_init_rcu_head(struct rcu_head *head) { -- cgit v0.10.2 From ce08b62d18b3f97cd4e5a39bd5898872b9201875 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 11 Jan 2014 19:19:53 +0100 Subject: change close_files() to use rcu_dereference_raw(files->fdt) put_files_struct() and close_files() do rcu_read_lock() to make rcu_dereference_check_fdtable() happy. This looks a bit ugly, files_fdtable() just reads the pointer, we can simply use rcu_dereference_raw() to avoid the warning. The patch also changes close_files() to return fdt, this avoids another rcu_read_lock()/files_fdtable() in put_files_struct(). I think close_files() needs more cleanups: - we do not need xchg() exactly because we are the last user of this files_struct - "if (file)" should be turned into WARN_ON(!file) Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/file.c b/fs/file.c index 957cbc0..d34e59e 100644 --- a/fs/file.c +++ b/fs/file.c @@ -348,21 +348,16 @@ out: return NULL; } -static void close_files(struct files_struct * files) +static struct fdtable *close_files(struct files_struct * files) { - int i, j; - struct fdtable *fdt; - - j = 0; - /* * It is safe to dereference the fd table without RCU or * ->file_lock because this is the last reference to the - * files structure. But use RCU to shut RCU-lockdep up. + * files structure. */ - rcu_read_lock(); - fdt = files_fdtable(files); - rcu_read_unlock(); + struct fdtable *fdt = rcu_dereference_raw(files->fdt); + int i, j = 0; + for (;;) { unsigned long set; i = j * BITS_PER_LONG; @@ -381,6 +376,8 @@ static void close_files(struct files_struct * files) set >>= 1; } } + + return fdt; } struct files_struct *get_files_struct(struct task_struct *task) @@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task) void put_files_struct(struct files_struct *files) { - struct fdtable *fdt; - if (atomic_dec_and_test(&files->count)) { - close_files(files); - /* not really needed, since nobody can see us */ - rcu_read_lock(); - fdt = files_fdtable(files); - rcu_read_unlock(); + struct fdtable *fdt = close_files(files); + /* free the arrays if they are not embedded */ if (fdt != &files->fdtab) __free_fdtable(fdt); -- cgit v0.10.2 From 1deb46e2562561255c34075825fd00f22a858bb3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 13 Jan 2014 16:48:19 +0100 Subject: fs: factor out common code in fget() and fget_raw() Apart from FMODE_PATH check fget() and fget_raw() are identical, shift the code into the new simple helper, __fget(fd, mask). Saves 160 bytes. Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/file.c b/fs/file.c index d34e59e..4ed58a3 100644 --- a/fs/file.c +++ b/fs/file.c @@ -637,16 +637,16 @@ void do_close_on_exec(struct files_struct *files) spin_unlock(&files->file_lock); } -struct file *fget(unsigned int fd) +static struct file *__fget(unsigned int fd, fmode_t mask) { - struct file *file; struct files_struct *files = current->files; + struct file *file; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { /* File object ref couldn't be taken */ - if (file->f_mode & FMODE_PATH || + if ((file->f_mode & mask) || !atomic_long_inc_not_zero(&file->f_count)) file = NULL; } @@ -655,25 +655,16 @@ struct file *fget(unsigned int fd) return file; } +struct file *fget(unsigned int fd) +{ + return __fget(fd, FMODE_PATH); +} EXPORT_SYMBOL(fget); struct file *fget_raw(unsigned int fd) { - struct file *file; - struct files_struct *files = current->files; - - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - /* File object ref couldn't be taken */ - if (!atomic_long_inc_not_zero(&file->f_count)) - file = NULL; - } - rcu_read_unlock(); - - return file; + return __fget(fd, 0); } - EXPORT_SYMBOL(fget_raw); /* -- cgit v0.10.2 From ad46183445043b562856c60b74db664668fb364b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 13 Jan 2014 16:48:40 +0100 Subject: fs: factor out common code in fget_light() and fget_raw_light() Apart from FMODE_PATH check fget_light() and fget_raw_light() are identical, shift the code into the new helper, __fget_light(fd, mask). Saves 208 bytes. Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/file.c b/fs/file.c index 4ed58a3..50c1208 100644 --- a/fs/file.c +++ b/fs/file.c @@ -683,21 +683,21 @@ EXPORT_SYMBOL(fget_raw); * The fput_needed flag returned by fget_light should be passed to the * corresponding fput_light. */ -struct file *fget_light(unsigned int fd, int *fput_needed) +struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed) { - struct file *file; struct files_struct *files = current->files; + struct file *file; *fput_needed = 0; if (atomic_read(&files->count) == 1) { file = __fcheck_files(files, fd); - if (file && (file->f_mode & FMODE_PATH)) + if (file && (file->f_mode & mask)) file = NULL; } else { rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - if (!(file->f_mode & FMODE_PATH) && + if (!(file->f_mode & mask) && atomic_long_inc_not_zero(&file->f_count)) *fput_needed = 1; else @@ -709,30 +709,15 @@ struct file *fget_light(unsigned int fd, int *fput_needed) return file; } +struct file *fget_light(unsigned int fd, int *fput_needed) +{ + return __fget_light(fd, FMODE_PATH, fput_needed); +} EXPORT_SYMBOL(fget_light); struct file *fget_raw_light(unsigned int fd, int *fput_needed) { - struct file *file; - struct files_struct *files = current->files; - - *fput_needed = 0; - if (atomic_read(&files->count) == 1) { - file = __fcheck_files(files, fd); - } else { - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (atomic_long_inc_not_zero(&file->f_count)) - *fput_needed = 1; - else - /* Didn't get the reference, someone's freed */ - file = NULL; - } - rcu_read_unlock(); - } - - return file; + return __fget_light(fd, 0, fput_needed); } void set_close_on_exec(unsigned int fd, int flag) -- cgit v0.10.2 From e6ff9a9fa4e05c1c03dec63cdc6a87d6dea02755 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 13 Jan 2014 16:49:06 +0100 Subject: fs: __fget_light() can use __fget() in slow path The slow path in __fget_light() can use __fget() to avoid the code duplication. Saves 232 bytes. Signed-off-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/file.c b/fs/file.c index 50c1208..771578b 100644 --- a/fs/file.c +++ b/fs/file.c @@ -694,17 +694,9 @@ struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed) if (file && (file->f_mode & mask)) file = NULL; } else { - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (!(file->f_mode & mask) && - atomic_long_inc_not_zero(&file->f_count)) - *fput_needed = 1; - else - /* Didn't get the reference, someone's freed */ - file = NULL; - } - rcu_read_unlock(); + file = __fget(fd, mask); + if (file) + *fput_needed = 1; } return file; -- cgit v0.10.2 From ac34a1b35eca5ef64cb499e25f776bf42a81a660 Mon Sep 17 00:00:00 2001 From: Rakesh Pandit Date: Wed, 15 Jan 2014 19:58:28 +0200 Subject: befs: iget_locked() doesn't return an ERR_PTR Also fix befs_iget return value if iget_locked fails. Signed-off-by: Rakesh Pandit Signed-off-by: Al Viro diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index daa15d6..845d2d6 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -324,8 +324,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino); inode = iget_locked(sb, ino); - if (IS_ERR(inode)) - return inode; + if (!inode) + return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; -- cgit v0.10.2 From 9dad943ae7d4a01da6bb18e1a157ab1bfe6186cd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:36 -0800 Subject: reiserfs: prefix ACL symbols with reiserfs_ Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 06c04f7..6f721ea 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -16,7 +16,7 @@ static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct posix_acl *acl); static int -posix_acl_set(struct dentry *dentry, const char *name, const void *value, +reiserfs_posix_acl_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct inode *inode = dentry->d_inode; @@ -65,7 +65,7 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value, } static int -posix_acl_get(struct dentry *dentry, const char *name, void *buffer, +reiserfs_posix_acl_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { struct posix_acl *acl; @@ -88,7 +88,7 @@ posix_acl_get(struct dentry *dentry, const char *name, void *buffer, /* * Convert from filesystem to in-memory representation. */ -static struct posix_acl *posix_acl_from_disk(const void *value, size_t size) +static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; int n, count; @@ -158,7 +158,7 @@ static struct posix_acl *posix_acl_from_disk(const void *value, size_t size) /* * Convert from in-memory to filesystem representation. */ -static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) +static void *reiserfs_posix_acl_to_disk(const struct posix_acl *acl, size_t * size) { reiserfs_acl_header *ext_acl; char *e; @@ -257,7 +257,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) } else if (retval < 0) { acl = ERR_PTR(retval); } else { - acl = posix_acl_from_disk(value, retval); + acl = reiserfs_posix_acl_from_disk(value, retval); } if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); @@ -307,7 +307,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, } if (acl) { - value = posix_acl_to_disk(acl, &size); + value = reiserfs_posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } @@ -499,8 +499,8 @@ static size_t posix_acl_access_list(struct dentry *dentry, char *list, const struct xattr_handler reiserfs_posix_acl_access_handler = { .prefix = POSIX_ACL_XATTR_ACCESS, .flags = ACL_TYPE_ACCESS, - .get = posix_acl_get, - .set = posix_acl_set, + .get = reiserfs_posix_acl_get, + .set = reiserfs_posix_acl_set, .list = posix_acl_access_list, }; @@ -519,7 +519,7 @@ static size_t posix_acl_default_list(struct dentry *dentry, char *list, const struct xattr_handler reiserfs_posix_acl_default_handler = { .prefix = POSIX_ACL_XATTR_DEFAULT, .flags = ACL_TYPE_DEFAULT, - .get = posix_acl_get, - .set = posix_acl_set, + .get = reiserfs_posix_acl_get, + .set = reiserfs_posix_acl_set, .list = posix_acl_default_list, }; -- cgit v0.10.2 From 5c8ebd57b6a51daf53f75b7a16c45090a98a91a4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:37 -0800 Subject: fs: merge xattr_acl.c into posix_acl.c Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/Makefile b/fs/Makefile index 4fe6df3..f2c1843 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o -obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o +obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_GENERIC_ACL) += generic_acl.o obj-$(CONFIG_COREDUMP) += coredump.o diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 8bd2135..359d70b 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -1,10 +1,8 @@ /* - * linux/fs/posix_acl.c + * Copyright (C) 2002,2003 by Andreas Gruenbacher * - * Copyright (C) 2002 by Andreas Gruenbacher - * - * Fixes from William Schumacher incorporated on 15 March 2001. - * (Reported by Charles Bertsch, ). + * Fixes from William Schumacher incorporated on 15 March 2001. + * (Reported by Charles Bertsch, ). */ /* @@ -18,9 +16,9 @@ #include #include #include +#include #include - -#include +#include EXPORT_SYMBOL(posix_acl_init); EXPORT_SYMBOL(posix_acl_alloc); @@ -418,3 +416,171 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) return err; } EXPORT_SYMBOL(posix_acl_chmod); + +/* + * Fix up the uids and gids in posix acl extended attributes in place. + */ +static void posix_acl_fix_xattr_userns( + struct user_namespace *to, struct user_namespace *from, + void *value, size_t size) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + int count; + kuid_t uid; + kgid_t gid; + + if (!value) + return; + if (size < sizeof(posix_acl_xattr_header)) + return; + if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return; + + count = posix_acl_xattr_count(size); + if (count < 0) + return; + if (count == 0) + return; + + for (end = entry + count; entry != end; entry++) { + switch(le16_to_cpu(entry->e_tag)) { + case ACL_USER: + uid = make_kuid(from, le32_to_cpu(entry->e_id)); + entry->e_id = cpu_to_le32(from_kuid(to, uid)); + break; + case ACL_GROUP: + gid = make_kgid(from, le32_to_cpu(entry->e_id)); + entry->e_id = cpu_to_le32(from_kgid(to, gid)); + break; + default: + break; + } + } +} + +void posix_acl_fix_xattr_from_user(void *value, size_t size) +{ + struct user_namespace *user_ns = current_user_ns(); + if (user_ns == &init_user_ns) + return; + posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); +} + +void posix_acl_fix_xattr_to_user(void *value, size_t size) +{ + struct user_namespace *user_ns = current_user_ns(); + if (user_ns == &init_user_ns) + return; + posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); +} + +/* + * Convert from extended attribute to in-memory representation. + */ +struct posix_acl * +posix_acl_from_xattr(struct user_namespace *user_ns, + const void *value, size_t size) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + int count; + struct posix_acl *acl; + struct posix_acl_entry *acl_e; + + if (!value) + return NULL; + if (size < sizeof(posix_acl_xattr_header)) + return ERR_PTR(-EINVAL); + if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return ERR_PTR(-EOPNOTSUPP); + + count = posix_acl_xattr_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = posix_acl_alloc(count, GFP_NOFS); + if (!acl) + return ERR_PTR(-ENOMEM); + acl_e = acl->a_entries; + + for (end = entry + count; entry != end; acl_e++, entry++) { + acl_e->e_tag = le16_to_cpu(entry->e_tag); + acl_e->e_perm = le16_to_cpu(entry->e_perm); + + switch(acl_e->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + break; + + case ACL_USER: + acl_e->e_uid = + make_kuid(user_ns, + le32_to_cpu(entry->e_id)); + if (!uid_valid(acl_e->e_uid)) + goto fail; + break; + case ACL_GROUP: + acl_e->e_gid = + make_kgid(user_ns, + le32_to_cpu(entry->e_id)); + if (!gid_valid(acl_e->e_gid)) + goto fail; + break; + + default: + goto fail; + } + } + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL (posix_acl_from_xattr); + +/* + * Convert from in-memory to extended attribute representation. + */ +int +posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, + void *buffer, size_t size) +{ + posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; + posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; + int real_size, n; + + real_size = posix_acl_xattr_size(acl->a_count); + if (!buffer) + return real_size; + if (real_size > size) + return -ERANGE; + + ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); + + for (n=0; n < acl->a_count; n++, ext_entry++) { + const struct posix_acl_entry *acl_e = &acl->a_entries[n]; + ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); + ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); + switch(acl_e->e_tag) { + case ACL_USER: + ext_entry->e_id = + cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); + break; + case ACL_GROUP: + ext_entry->e_id = + cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); + break; + default: + ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); + break; + } + } + return real_size; +} +EXPORT_SYMBOL (posix_acl_to_xattr); diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c deleted file mode 100644 index 9fbea87..0000000 --- a/fs/xattr_acl.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * linux/fs/xattr_acl.c - * - * Almost all from linux/fs/ext2/acl.c: - * Copyright (C) 2001 by Andreas Gruenbacher, - */ - -#include -#include -#include -#include -#include - -/* - * Fix up the uids and gids in posix acl extended attributes in place. - */ -static void posix_acl_fix_xattr_userns( - struct user_namespace *to, struct user_namespace *from, - void *value, size_t size) -{ - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; - int count; - kuid_t uid; - kgid_t gid; - - if (!value) - return; - if (size < sizeof(posix_acl_xattr_header)) - return; - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return; - - count = posix_acl_xattr_count(size); - if (count < 0) - return; - if (count == 0) - return; - - for (end = entry + count; entry != end; entry++) { - switch(le16_to_cpu(entry->e_tag)) { - case ACL_USER: - uid = make_kuid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kuid(to, uid)); - break; - case ACL_GROUP: - gid = make_kgid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kgid(to, gid)); - break; - default: - break; - } - } -} - -void posix_acl_fix_xattr_from_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); -} - -void posix_acl_fix_xattr_to_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); -} - -/* - * Convert from extended attribute to in-memory representation. - */ -struct posix_acl * -posix_acl_from_xattr(struct user_namespace *user_ns, - const void *value, size_t size) -{ - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; - int count; - struct posix_acl *acl; - struct posix_acl_entry *acl_e; - - if (!value) - return NULL; - if (size < sizeof(posix_acl_xattr_header)) - return ERR_PTR(-EINVAL); - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return ERR_PTR(-EOPNOTSUPP); - - count = posix_acl_xattr_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - - acl = posix_acl_alloc(count, GFP_NOFS); - if (!acl) - return ERR_PTR(-ENOMEM); - acl_e = acl->a_entries; - - for (end = entry + count; entry != end; acl_e++, entry++) { - acl_e->e_tag = le16_to_cpu(entry->e_tag); - acl_e->e_perm = le16_to_cpu(entry->e_perm); - - switch(acl_e->e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - break; - - case ACL_USER: - acl_e->e_uid = - make_kuid(user_ns, - le32_to_cpu(entry->e_id)); - if (!uid_valid(acl_e->e_uid)) - goto fail; - break; - case ACL_GROUP: - acl_e->e_gid = - make_kgid(user_ns, - le32_to_cpu(entry->e_id)); - if (!gid_valid(acl_e->e_gid)) - goto fail; - break; - - default: - goto fail; - } - } - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} -EXPORT_SYMBOL (posix_acl_from_xattr); - -/* - * Convert from in-memory to extended attribute representation. - */ -int -posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, - void *buffer, size_t size) -{ - posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; - posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; - int real_size, n; - - real_size = posix_acl_xattr_size(acl->a_count); - if (!buffer) - return real_size; - if (real_size > size) - return -ERANGE; - - ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); - - for (n=0; n < acl->a_count; n++, ext_entry++) { - const struct posix_acl_entry *acl_e = &acl->a_entries[n]; - ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); - ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); - switch(acl_e->e_tag) { - case ACL_USER: - ext_entry->e_id = - cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); - break; - case ACL_GROUP: - ext_entry->e_id = - cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); - break; - default: - ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); - break; - } - } - return real_size; -} -EXPORT_SYMBOL (posix_acl_to_xattr); -- cgit v0.10.2 From 2982baa2ae31eb23ce29b688ab2f77eb019062f3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:38 -0800 Subject: fs: add get_acl helper Factor out the code to get an ACL either from the inode or disk from check_acl, so that it can be used elsewhere later on. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index 3531dee..bcb838e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -235,27 +235,9 @@ static int check_acl(struct inode *inode, int mask) return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); } - acl = get_cached_acl(inode, ACL_TYPE_ACCESS); - - /* - * A filesystem can force a ACL callback by just never filling the - * ACL cache. But normally you'd fill the cache either at inode - * instantiation time, or on the first ->get_acl call. - * - * If the filesystem doesn't have a get_acl() function at all, we'll - * just create the negative cache entry. - */ - if (acl == ACL_NOT_CACHED) { - if (inode->i_op->get_acl) { - acl = inode->i_op->get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } else { - set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); - return -EAGAIN; - } - } - + acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); if (acl) { int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 359d70b..30524de 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -26,6 +26,33 @@ EXPORT_SYMBOL(posix_acl_valid); EXPORT_SYMBOL(posix_acl_equiv_mode); EXPORT_SYMBOL(posix_acl_from_mode); +struct posix_acl *get_acl(struct inode *inode, int type) +{ + struct posix_acl *acl; + + acl = get_cached_acl(inode, type); + if (acl != ACL_NOT_CACHED) + return acl; + + if (!IS_POSIXACL(inode)) + return NULL; + + /* + * A filesystem can force a ACL callback by just never filling the + * ACL cache. But normally you'd fill the cache either at inode + * instantiation time, or on the first ->get_acl call. + * + * If the filesystem doesn't have a get_acl() function at all, we'll + * just create the negative cache entry. + */ + if (!inode->i_op->get_acl) { + set_cached_acl(inode, type, NULL); + return NULL; + } + return inode->i_op->get_acl(inode, type); +} +EXPORT_SYMBOL(get_acl); + /* * Init a fresh posix_acl */ diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 7931efe..a8d9918 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -175,4 +175,6 @@ static inline void cache_no_acl(struct inode *inode) #endif } +struct posix_acl *get_acl(struct inode *inode, int type); + #endif /* __LINUX_POSIX_ACL_H */ -- cgit v0.10.2 From 893d46e443346370cd4ea81d9d35f72952c62a37 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:39 -0800 Subject: fs: add a set_acl inode operation This will allow moving all the Posix ACL handling into the VFS and clean up tons of cruft in the filesystems. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/include/linux/fs.h b/include/linux/fs.h index 121f11f..09f553c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1580,6 +1580,7 @@ struct inode_operations { struct file *, unsigned open_flag, umode_t create_mode, int *opened); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*set_acl)(struct inode *, struct posix_acl *, int); } ____cacheline_aligned; ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, -- cgit v0.10.2 From 2aeccbe957d0d2b9fbb2a236e53a955097e2a9ce Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:40 -0800 Subject: fs: add generic xattr_acl handlers With the ->set_acl inode operation we can implement the Posix ACL xattr handlers in generic code instead of duplicating them all over the tree. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 30524de..e699b07 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -611,3 +612,104 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, return real_size; } EXPORT_SYMBOL (posix_acl_to_xattr); + +static int +posix_acl_xattr_get(struct dentry *dentry, const char *name, + void *value, size_t size, int type) +{ + struct posix_acl *acl; + int error; + + if (!IS_POSIXACL(dentry->d_inode)) + return -EOPNOTSUPP; + if (S_ISLNK(dentry->d_inode->i_mode)) + return -EOPNOTSUPP; + + acl = get_acl(dentry->d_inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + + error = posix_acl_to_xattr(&init_user_ns, acl, value, size); + posix_acl_release(acl); + + return error; +} + +static int +posix_acl_xattr_set(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct inode *inode = dentry->d_inode; + struct posix_acl *acl = NULL; + int ret; + + if (!IS_POSIXACL(inode)) + return -EOPNOTSUPP; + if (!inode->i_op->set_acl) + return -EOPNOTSUPP; + + if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) + return value ? -EACCES : 0; + if (!inode_owner_or_capable(inode)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(&init_user_ns, value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + + if (acl) { + ret = posix_acl_valid(acl); + if (ret) + goto out; + } + } + + ret = inode->i_op->set_acl(inode, acl, type); +out: + posix_acl_release(acl); + return ret; +} + +static size_t +posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size, + const char *name, size_t name_len, int type) +{ + const char *xname; + size_t size; + + if (!IS_POSIXACL(dentry->d_inode)) + return -EOPNOTSUPP; + if (S_ISLNK(dentry->d_inode->i_mode)) + return -EOPNOTSUPP; + + if (type == ACL_TYPE_ACCESS) + xname = POSIX_ACL_XATTR_ACCESS; + else + xname = POSIX_ACL_XATTR_DEFAULT; + + size = strlen(xname) + 1; + if (list && size <= list_size) + memcpy(list, xname, size); + return size; +} + +const struct xattr_handler posix_acl_access_xattr_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .flags = ACL_TYPE_ACCESS, + .list = posix_acl_xattr_list, + .get = posix_acl_xattr_get, + .set = posix_acl_xattr_set, +}; +EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); + +const struct xattr_handler posix_acl_default_xattr_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .flags = ACL_TYPE_DEFAULT, + .list = posix_acl_xattr_list, + .get = posix_acl_xattr_get, + .set = posix_acl_xattr_set, +}; +EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h index ad93ad0..6f14ee2 100644 --- a/include/linux/posix_acl_xattr.h +++ b/include/linux/posix_acl_xattr.h @@ -69,4 +69,7 @@ struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns, int posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, void *buffer, size_t size); +extern const struct xattr_handler posix_acl_access_xattr_handler; +extern const struct xattr_handler posix_acl_default_xattr_handler; + #endif /* _POSIX_ACL_XATTR_H */ -- cgit v0.10.2 From 5bf3258fd2acd8515450ab8efcd97c9d3b69f7f9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:41 -0800 Subject: fs: make posix_acl_chmod more useful Rename the current posix_acl_chmod to __posix_acl_chmod and add a fully featured ACL chmod helper that uses the ->set_acl inode operation. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 7af425f..f5ce5c5 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -156,7 +156,7 @@ int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid) return -EOPNOTSUPP; acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { - retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + retval = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (retval) return retval; set_cached_acl(inode, ACL_TYPE_ACCESS, acl); diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 0890c83..1af04ff 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -256,7 +256,7 @@ int btrfs_acl_chmod(struct inode *inode) if (IS_ERR_OR_NULL(acl)) return PTR_ERR(acl); - ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (ret) return ret; ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS); diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 110b6b3..7006ced 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -308,7 +308,7 @@ ext2_acl_chmod(struct inode *inode) 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); + error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index dbb5ad5..6691a6c 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -314,7 +314,7 @@ ext3_acl_chmod(struct inode *inode) acl = ext3_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); + error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; retry: diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 39a54a0..2eebe02 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -320,7 +320,7 @@ ext4_acl_chmod(struct inode *inode) acl = ext4_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); + error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; retry: diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index d0fc287..14c4df0 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -311,7 +311,7 @@ int f2fs_acl_chmod(struct inode *inode) if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, mode); + error = __posix_acl_chmod(&acl, GFP_KERNEL, mode); if (error) return error; diff --git a/fs/generic_acl.c b/fs/generic_acl.c index b3f3676..46a5076 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -158,7 +158,7 @@ generic_acl_chmod(struct inode *inode) return -EOPNOTSUPP; acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; set_cached_acl(inode, ACL_TYPE_ACCESS, acl); diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index f69ac0a..3e200c7 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -162,7 +162,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) if (!acl) return gfs2_setattr_simple(inode, attr); - error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode); + error = __posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode); if (error) return error; diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c index b609cc1..cab5fd6 100644 --- a/fs/hfsplus/posix_acl.c +++ b/fs/hfsplus/posix_acl.c @@ -167,7 +167,7 @@ int hfsplus_posix_acl_chmod(struct inode *inode) if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + err = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (unlikely(err)) return err; diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 223283c..5853969 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -335,7 +335,7 @@ int jffs2_acl_chmod(struct inode *inode) acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (rc) return rc; rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl); diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index d254d6d..9c0fca8 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -161,7 +161,7 @@ int jfs_acl_chmod(struct inode *inode) if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (rc) return rc; diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index b4f788e..73ccf0e 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -350,7 +350,7 @@ int ocfs2_acl_chmod(struct inode *inode) acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (ret) return ret; ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, diff --git a/fs/posix_acl.c b/fs/posix_acl.c index e699b07..0821855 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -364,7 +364,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) /* * Modify the ACL for the chmod syscall. */ -static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) +static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) { struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; struct posix_acl_entry *pa, *pe; @@ -428,12 +428,12 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) EXPORT_SYMBOL(posix_acl_create); int -posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) +__posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; if (clone) { - err = posix_acl_chmod_masq(clone, mode); + err = __posix_acl_chmod_masq(clone, mode); if (err) { posix_acl_release(clone); clone = NULL; @@ -443,6 +443,30 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) *acl = clone; return err; } +EXPORT_SYMBOL(__posix_acl_chmod); + +int +posix_acl_chmod(struct inode *inode) +{ + struct posix_acl *acl; + int ret = 0; + + if (!IS_POSIXACL(inode)) + return 0; + if (!inode->i_op->set_acl) + return -EOPNOTSUPP; + + acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR_OR_NULL(acl)) + return PTR_ERR(acl); + + ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + if (ret) + return ret; + ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + return ret; +} EXPORT_SYMBOL(posix_acl_chmod); /* diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 6f721ea..ea4e443 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -463,7 +463,7 @@ int reiserfs_acl_chmod(struct inode *inode) return 0; if (IS_ERR(acl)) return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode); + error = __posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode); if (error) return error; diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 370eb3e..4eac105 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -334,7 +334,7 @@ xfs_acl_chmod(struct inode *inode) if (IS_ERR(acl) || !acl) return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index a8d9918..8b64e78 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -89,12 +89,14 @@ extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); -extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); +extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); extern struct posix_acl *get_posix_acl(struct inode *, int); extern int set_posix_acl(struct inode *, int, struct posix_acl *); #ifdef CONFIG_FS_POSIX_ACL +extern int posix_acl_chmod(struct inode *); + static inline struct posix_acl **acl_by_type(struct inode *inode, int type) { switch (type) { @@ -165,15 +167,22 @@ static inline void forget_all_cached_acls(struct inode *inode) if (old_default != ACL_NOT_CACHED) posix_acl_release(old_default); } -#endif static inline void cache_no_acl(struct inode *inode) { -#ifdef CONFIG_FS_POSIX_ACL inode->i_acl = NULL; inode->i_default_acl = NULL; -#endif } +#else +static inline int posix_acl_chmod(struct inode *inode) +{ + return 0; +} + +static inline void cache_no_acl(struct inode *inode) +{ +} +#endif /* CONFIG_FS_POSIX_ACL */ struct posix_acl *get_acl(struct inode *inode, int type); -- cgit v0.10.2 From 37bc15392a2363ca822b2c2828e0ccafbea32f75 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:42 -0800 Subject: fs: make posix_acl_create more useful Rename the current posix_acl_created to __posix_acl_create and add a fully featured helper to set up the ACLs on file creation that uses get_acl(). Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/9p/acl.c b/fs/9p/acl.c index f5ce5c5..8482f2d 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -200,7 +200,7 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep, if (acl) { if (S_ISDIR(mode)) *dpacl = posix_acl_dup(acl); - retval = posix_acl_create(&acl, GFP_NOFS, &mode); + retval = __posix_acl_create(&acl, GFP_NOFS, &mode); if (retval < 0) return retval; if (retval > 0) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 1af04ff..b56519d 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -222,7 +222,7 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans, if (ret) goto failed; } - ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + ret = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (ret < 0) return ret; diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 7006ced..6e842a7 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -268,7 +268,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir) if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) { diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 6691a6c..4f3d8fa 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -271,7 +271,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (error < 0) return error; diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 2eebe02..f827f3b 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -276,7 +276,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (error < 0) return error; diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 14c4df0..45e8430 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -285,7 +285,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) diff --git a/fs/generic_acl.c b/fs/generic_acl.c index 46a5076..4357f39 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -128,7 +128,7 @@ generic_acl_init(struct inode *inode, struct inode *dir) if (acl) { if (S_ISDIR(inode->i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 3e200c7..e82e4ac 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -131,7 +131,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) goto out; } - error = posix_acl_create(&acl, GFP_NOFS, &mode); + error = __posix_acl_create(&acl, GFP_NOFS, &mode); if (error < 0) return error; diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c index cab5fd6..277942f 100644 --- a/fs/hfsplus/posix_acl.c +++ b/fs/hfsplus/posix_acl.c @@ -137,7 +137,7 @@ int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) goto init_acl_cleanup; } - err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (unlikely(err < 0)) return err; diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 5853969..4d6e31b 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -295,7 +295,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode if (S_ISDIR(*i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - rc = posix_acl_create(&acl, GFP_KERNEL, i_mode); + rc = __posix_acl_create(&acl, GFP_KERNEL, i_mode); if (rc < 0) return rc; if (rc > 0) diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 9c0fca8..28d529a 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -132,7 +132,7 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) if (rc) goto cleanup; } - rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + rc = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (rc < 0) goto cleanup; /* posix_acl_release(NULL) is no-op */ if (rc > 0) diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 4a1aafb..e859675 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -428,7 +428,7 @@ int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, if (!dfacl) return 0; acl = posix_acl_dup(dfacl); - error = posix_acl_create(&acl, GFP_KERNEL, &mode); + error = __posix_acl_create(&acl, GFP_KERNEL, &mode); if (error < 0) goto out_release_dfacl; error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 73ccf0e..c0f9d2f 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -401,7 +401,7 @@ int ocfs2_init_acl(handle_t *handle, goto cleanup; } mode = inode->i_mode; - ret = posix_acl_create(&acl, GFP_NOFS, &mode); + ret = __posix_acl_create(&acl, GFP_NOFS, &mode); if (ret < 0) return ret; diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 0821855..8f245ab 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -410,7 +410,7 @@ static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) } int -posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) +__posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; @@ -425,7 +425,7 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) *acl = clone; return err; } -EXPORT_SYMBOL(posix_acl_create); +EXPORT_SYMBOL(__posix_acl_create); int __posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) @@ -446,7 +446,7 @@ __posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) EXPORT_SYMBOL(__posix_acl_chmod); int -posix_acl_chmod(struct inode *inode) +posix_acl_chmod(struct inode *inode, umode_t mode) { struct posix_acl *acl; int ret = 0; @@ -460,7 +460,7 @@ posix_acl_chmod(struct inode *inode) if (IS_ERR_OR_NULL(acl)) return PTR_ERR(acl); - ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode); if (ret) return ret; ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS); @@ -469,6 +469,55 @@ posix_acl_chmod(struct inode *inode) } EXPORT_SYMBOL(posix_acl_chmod); +int +posix_acl_create(struct inode *dir, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl) +{ + struct posix_acl *p; + int ret; + + if (S_ISLNK(*mode) || !IS_POSIXACL(dir)) + goto no_acl; + + p = get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (!p) { + *mode &= ~current_umask(); + goto no_acl; + } + + *acl = posix_acl_clone(p, GFP_NOFS); + if (!*acl) + return -ENOMEM; + + ret = posix_acl_create_masq(*acl, mode); + if (ret < 0) { + posix_acl_release(*acl); + return -ENOMEM; + } + + if (ret == 0) { + posix_acl_release(*acl); + *acl = NULL; + } + + if (!S_ISDIR(*mode)) { + posix_acl_release(p); + *default_acl = NULL; + } else { + *default_acl = p; + } + return 0; + +no_acl: + *default_acl = NULL; + *acl = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(posix_acl_create); + /* * Fix up the uids and gids in posix acl extended attributes in place. */ diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index ea4e443..d95c959 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -378,7 +378,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, /* Now we reconcile the new ACL and the mode, potentially modifying both */ - err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (err < 0) return err; diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 4eac105..057ae2d 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -297,12 +297,12 @@ xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) goto out; } - error = posix_acl_create(&acl, GFP_KERNEL, &mode); + error = __posix_acl_create(&acl, GFP_KERNEL, &mode); if (error < 0) return error; /* - * If posix_acl_create returns a positive value we need to + * If __posix_acl_create returns a positive value we need to * inherit a permission that can't be represented using the Unix * mode bits and we actually need to set an ACL. */ diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 8b64e78..f7e6f6c 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -88,14 +88,16 @@ extern int posix_acl_valid(const struct posix_acl *); extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); -extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); +extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *); extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); extern struct posix_acl *get_posix_acl(struct inode *, int); extern int set_posix_acl(struct inode *, int, struct posix_acl *); #ifdef CONFIG_FS_POSIX_ACL -extern int posix_acl_chmod(struct inode *); +extern int posix_acl_chmod(struct inode *, umode_t); +extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, + struct posix_acl **); static inline struct posix_acl **acl_by_type(struct inode *inode, int type) { @@ -174,7 +176,7 @@ static inline void cache_no_acl(struct inode *inode) inode->i_default_acl = NULL; } #else -static inline int posix_acl_chmod(struct inode *inode) +static inline int posix_acl_chmod(struct inode *inode, umode_t mode) { return 0; } @@ -182,6 +184,13 @@ static inline int posix_acl_chmod(struct inode *inode) static inline void cache_no_acl(struct inode *inode) { } + +static inline int posix_acl_create(struct inode *inode, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl) +{ + *default_acl = *acl = NULL; + return 0; +} #endif /* CONFIG_FS_POSIX_ACL */ struct posix_acl *get_acl(struct inode *inode, int type); -- cgit v0.10.2 From 996a710d46418cacb5b4a519ab9341a74066551d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:43 -0800 Subject: btrfs: use generic posix ACL infrastructure Also don't bother to set up a .get_acl method for symlinks as we do not support access control (ACLs or even mode bits) for symlinks in Linux. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index b56519d..ff9b399 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -35,13 +35,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) char *value = NULL; struct posix_acl *acl; - if (!IS_POSIXACL(inode)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -76,31 +69,10 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) return acl; } -static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name, - void *value, size_t size, int type) -{ - struct posix_acl *acl; - int ret = 0; - - if (!IS_POSIXACL(dentry->d_inode)) - return -EOPNOTSUPP; - - acl = btrfs_get_acl(dentry->d_inode, type); - - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); - posix_acl_release(acl); - - return ret; -} - /* * Needs to be called with fs_mutex held */ -static int btrfs_set_acl(struct btrfs_trans_handle *trans, +static int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct posix_acl *acl, int type) { int ret, size = 0; @@ -158,35 +130,9 @@ out: return ret; } -static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) +int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - int ret; - struct posix_acl *acl = NULL; - - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (!IS_POSIXACL(dentry->d_inode)) - return -EOPNOTSUPP; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (acl) { - ret = posix_acl_valid(acl); - if (ret) - goto out; - } - } - - ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type); -out: - posix_acl_release(acl); - - return ret; + return __btrfs_set_acl(NULL, inode, acl, type); } /* @@ -197,83 +143,31 @@ out: int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; int ret = 0; /* this happens with subvols */ if (!dir) return 0; - if (!S_ISLNK(inode->i_mode)) { - if (IS_POSIXACL(dir)) { - acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } + ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (ret) + return ret; - if (!acl) - inode->i_mode &= ~current_umask(); + if (default_acl) { + ret = __btrfs_set_acl(trans, inode, default_acl, + ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); } - if (IS_POSIXACL(dir) && acl) { - if (S_ISDIR(inode->i_mode)) { - ret = btrfs_set_acl(trans, inode, acl, - ACL_TYPE_DEFAULT); - if (ret) - goto failed; - } - ret = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (ret < 0) - return ret; - - if (ret > 0) { - /* we need an acl */ - ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); - } else if (ret < 0) { - cache_no_acl(inode); - } - } else { - cache_no_acl(inode); + if (acl) { + if (!ret) + ret = __btrfs_set_acl(trans, inode, acl, + ACL_TYPE_ACCESS); + posix_acl_release(acl); } -failed: - posix_acl_release(acl); - - return ret; -} -int btrfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int ret = 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!IS_POSIXACL(inode)) - return 0; - - acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR_OR_NULL(acl)) - return PTR_ERR(acl); - - ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (ret) - return ret; - ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS); - posix_acl_release(acl); + if (!default_acl && !acl) + cache_no_acl(inode); return ret; } - -const struct xattr_handler btrfs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = btrfs_xattr_acl_get, - .set = btrfs_xattr_acl_set, -}; - -const struct xattr_handler btrfs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = btrfs_xattr_acl_get, - .set = btrfs_xattr_acl_set, -}; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 54ab861..7506825 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3899,20 +3899,17 @@ do { \ /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL struct posix_acl *btrfs_get_acl(struct inode *inode, int type); +int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir); -int btrfs_acl_chmod(struct inode *inode); #else #define btrfs_get_acl NULL +#define btrfs_set_acl NULL static inline int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { return 0; } -static inline int btrfs_acl_chmod(struct inode *inode) -{ - return 0; -} #endif /* relocation.c */ diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f1a7744..b131430 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4464,7 +4464,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) err = btrfs_dirty_inode(inode); if (!err && attr->ia_valid & ATTR_MODE) - err = btrfs_acl_chmod(inode); + err = posix_acl_chmod(inode, inode->i_mode); } return err; @@ -8649,12 +8649,14 @@ static const struct inode_operations btrfs_dir_inode_operations = { .removexattr = btrfs_removexattr, .permission = btrfs_permission, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_dir_ro_inode_operations = { .lookup = btrfs_lookup, .permission = btrfs_permission, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; @@ -8724,6 +8726,7 @@ static const struct inode_operations btrfs_file_inode_operations = { .permission = btrfs_permission, .fiemap = btrfs_fiemap, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_special_inode_operations = { @@ -8735,6 +8738,7 @@ static const struct inode_operations btrfs_special_inode_operations = { .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_symlink_inode_operations = { @@ -8748,7 +8752,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .get_acl = btrfs_get_acl, .update_time = btrfs_update_time, }; diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 05740b9..3d1c301 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "ctree.h" #include "btrfs_inode.h" #include "transaction.h" @@ -313,8 +314,8 @@ err: */ const struct xattr_handler *btrfs_xattr_handlers[] = { #ifdef CONFIG_BTRFS_FS_POSIX_ACL - &btrfs_xattr_acl_access_handler, - &btrfs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL, }; diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h index b3cc803..5049608 100644 --- a/fs/btrfs/xattr.h +++ b/fs/btrfs/xattr.h @@ -21,8 +21,6 @@ #include -extern const struct xattr_handler btrfs_xattr_acl_access_handler; -extern const struct xattr_handler btrfs_xattr_acl_default_handler; extern const struct xattr_handler *btrfs_xattr_handlers[]; extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name, -- cgit v0.10.2 From 64e178a7118b1cf7648391755e44dcc209091003 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:44 -0800 Subject: ext2/3/4: use generic posix ACL infrastructure Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 6e842a7..1b8001b 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -148,13 +148,6 @@ ext2_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -189,19 +182,14 @@ ext2_get_acl(struct inode *inode, int type) /* * inode->i_mutex: down */ -static int -ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +int +ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int name_index; void *value = NULL; size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - switch(type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -250,169 +238,21 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) int ext2_init_acl(struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) { - /* This is an extended ACL */ - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - 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; - int error; + struct posix_acl *default_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); + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return error; -} -/* - * Extended attribut handlers - */ -static size_t -ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext2_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 = ext2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, 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; - - error = ext2_set_acl(dentry->d_inode, type, acl); - -release_and_out: - posix_acl_release(acl); + if (default_acl) { + error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + } return error; } - -const struct xattr_handler ext2_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext2_xattr_list_acl_access, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; - -const struct xattr_handler ext2_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext2_xattr_list_acl_default, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index 503bfb0..44937f9 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h @@ -55,7 +55,7 @@ static inline int ext2_acl_count(size_t size) /* acl.c */ extern struct posix_acl *ext2_get_acl(struct inode *inode, int type); -extern int ext2_acl_chmod (struct inode *); +extern int ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext2_init_acl (struct inode *, struct inode *); #else @@ -63,12 +63,6 @@ extern int ext2_init_acl (struct inode *, struct inode *); #define ext2_get_acl NULL #define ext2_set_acl NULL -static inline int -ext2_acl_chmod (struct inode *inode) -{ - return 0; -} - static inline int ext2_init_acl (struct inode *inode, struct inode *dir) { return 0; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index a5b3a5d..44c36e5 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -103,5 +103,6 @@ const struct inode_operations ext2_file_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, .fiemap = ext2_fiemap, }; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 8a33764..94ed3684 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1566,7 +1566,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) } setattr_copy(inode, iattr); if (iattr->ia_valid & ATTR_MODE) - error = ext2_acl_chmod(inode); + error = posix_acl_chmod(inode, inode->i_mode); mark_inode_dirty(inode); return error; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 256dd5f..c268d0a 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -421,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, .tmpfile = ext2_tmpfile, }; @@ -433,4 +434,5 @@ const struct inode_operations ext2_special_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, }; diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 2d7557d..9142614 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -103,8 +103,8 @@ static struct mb_cache *ext2_xattr_cache; static const struct xattr_handler *ext2_xattr_handler_map[] = { [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, #ifdef CONFIG_EXT2_FS_POSIX_ACL - [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext2_xattr_acl_access_handler, - [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler, + [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler, #ifdef CONFIG_EXT2_FS_SECURITY @@ -116,8 +116,8 @@ const struct xattr_handler *ext2_xattr_handlers[] = { &ext2_xattr_user_handler, &ext2_xattr_trusted_handler, #ifdef CONFIG_EXT2_FS_POSIX_ACL - &ext2_xattr_acl_access_handler, - &ext2_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT2_FS_SECURITY &ext2_xattr_security_handler, diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index 5e41ccc..60edf29 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -57,8 +57,6 @@ struct ext2_xattr_entry { extern const struct xattr_handler ext2_xattr_user_handler; extern const struct xattr_handler ext2_xattr_trusted_handler; -extern const struct xattr_handler ext2_xattr_acl_access_handler; -extern const struct xattr_handler ext2_xattr_acl_default_handler; extern const struct xattr_handler ext2_xattr_security_handler; extern ssize_t ext2_listxattr(struct dentry *, char *, size_t); diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 4f3d8fa..8bbaf5b 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -145,13 +145,6 @@ ext3_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -190,7 +183,7 @@ ext3_get_acl(struct inode *inode, int type) * inode->i_mutex: down unless called from ext3_new_inode */ static int -ext3_set_acl(handle_t *handle, struct inode *inode, int type, +__ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { int name_index; @@ -198,9 +191,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -243,204 +233,49 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -/* - * Initialize the ACLs of a new inode. Called from ext3_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext3_set_acl(handle, inode, - ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (error < 0) - return error; - - if (error > 0) { - /* This is an extended ACL */ - error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - 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 -ext3_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; handle_t *handle; - int retries = 0; - int error; + int error, retries = 0; - 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); - error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; 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, acl); + 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)) + if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; -out: - posix_acl_release(acl); return error; } /* - * Extended attribute handlers + * Initialize the ACLs of a new inode. Called from ext3_new_inode. + * + * dir->i_mutex: down + * inode->i_mutex: up (access to inode is still exclusive) */ -static size_t -ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) +int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int error; - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ext3_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext3_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(&init_user_ns, 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; + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; -release_and_out: - posix_acl_release(acl); + if (default_acl) { + error = __ext3_set_acl(handle, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = __ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, + acl); + posix_acl_release(acl); + } return error; } - -const struct xattr_handler ext3_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext3_xattr_list_acl_access, - .get = ext3_xattr_get_acl, - .set = ext3_xattr_set_acl, -}; - -const struct xattr_handler ext3_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext3_xattr_list_acl_default, - .get = ext3_xattr_get_acl, - .set = ext3_xattr_set_acl, -}; diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index dbc921e..ea1c69e 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h @@ -55,18 +55,13 @@ static inline int ext3_acl_count(size_t size) /* acl.c */ extern struct posix_acl *ext3_get_acl(struct inode *inode, int type); -extern int ext3_acl_chmod (struct inode *); +extern int ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT3_FS_POSIX_ACL */ #include #define ext3_get_acl NULL - -static inline int -ext3_acl_chmod(struct inode *inode) -{ - return 0; -} +#define ext3_set_acl NULL static inline int ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 25cb413..aad0531 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -75,6 +75,7 @@ const struct inode_operations ext3_file_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, .fiemap = ext3_fiemap, }; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 2bd8548..384b6eb 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3365,7 +3365,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) mark_inode_dirty(inode); if (ia_valid & ATTR_MODE) - rc = ext3_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); err_out: ext3_std_error(inode->i_sb, error); diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index f8cde46..f197736 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2569,6 +2569,7 @@ const struct inode_operations ext3_dir_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, }; const struct inode_operations ext3_special_inode_operations = { @@ -2580,4 +2581,5 @@ const struct inode_operations ext3_special_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, }; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index b1fc963..c6874be 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -102,8 +102,8 @@ static struct mb_cache *ext3_xattr_cache; static const struct xattr_handler *ext3_xattr_handler_map[] = { [EXT3_XATTR_INDEX_USER] = &ext3_xattr_user_handler, #ifdef CONFIG_EXT3_FS_POSIX_ACL - [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext3_xattr_acl_access_handler, - [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler, + [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT3_XATTR_INDEX_TRUSTED] = &ext3_xattr_trusted_handler, #ifdef CONFIG_EXT3_FS_SECURITY @@ -115,8 +115,8 @@ const struct xattr_handler *ext3_xattr_handlers[] = { &ext3_xattr_user_handler, &ext3_xattr_trusted_handler, #ifdef CONFIG_EXT3_FS_POSIX_ACL - &ext3_xattr_acl_access_handler, - &ext3_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT3_FS_SECURITY &ext3_xattr_security_handler, diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index 2be4f69..32e93eb 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -60,8 +60,6 @@ struct ext3_xattr_entry { extern const struct xattr_handler ext3_xattr_user_handler; extern const struct xattr_handler ext3_xattr_trusted_handler; -extern const struct xattr_handler ext3_xattr_acl_access_handler; -extern const struct xattr_handler ext3_xattr_acl_default_handler; extern const struct xattr_handler ext3_xattr_security_handler; extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index f827f3b..d40c8db 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -152,13 +152,6 @@ ext4_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -196,7 +189,7 @@ ext4_get_acl(struct inode *inode, int type) * inode->i_mutex: down unless called from ext4_new_inode */ static int -ext4_set_acl(handle_t *handle, struct inode *inode, int type, +__ext4_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { int name_index; @@ -204,9 +197,6 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -248,208 +238,51 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -/* - * Initialize the ACLs of a new inode. Called from ext4_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ int -ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext4_set_acl(handle, inode, - ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (error < 0) - return error; - - if (error > 0) { - /* This is an extended ACL */ - error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - 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 -ext4_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; handle_t *handle; - int retries = 0; - int error; - + int error, retries = 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - acl = ext4_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; retry: handle = ext4_journal_start(inode, EXT4_HT_XATTR, ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - ext4_std_error(inode->i_sb, error); - goto out; - } - error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + error = __ext4_set_acl(handle, inode, type, acl); ext4_journal_stop(handle); - if (error == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) + if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; -out: - posix_acl_release(acl); return error; } /* - * Extended attribute handlers + * Initialize the ACLs of a new inode. Called from ext4_new_inode. + * + * dir->i_mutex: down + * inode->i_mutex: up (access to inode is still exclusive) */ -static size_t -ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) +int +ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { - struct posix_acl *acl; + struct posix_acl *default_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(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -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(&init_user_ns, 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; + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; -retry: - handle = ext4_journal_start(inode, EXT4_HT_XATTR, - ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto release_and_out; + if (default_acl) { + error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, + acl); + posix_acl_release(acl); } - 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; } - -const struct xattr_handler ext4_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext4_xattr_list_acl_access, - .get = ext4_xattr_get_acl, - .set = ext4_xattr_set_acl, -}; - -const struct xattr_handler ext4_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext4_xattr_list_acl_default, - .get = ext4_xattr_get_acl, - .set = ext4_xattr_set_acl, -}; diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 18cb39e..da2c795 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h @@ -55,18 +55,13 @@ static inline int ext4_acl_count(size_t size) /* acl.c */ struct posix_acl *ext4_get_acl(struct inode *inode, int type); -extern int ext4_acl_chmod(struct inode *); +int ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT4_FS_POSIX_ACL */ #include #define ext4_get_acl NULL - -static inline int -ext4_acl_chmod(struct inode *inode) -{ - return 0; -} +#define ext4_set_acl NULL static inline int ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3da2194..43e64f6 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -617,6 +617,7 @@ const struct inode_operations ext4_file_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, }; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 61d49ff..23983c2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4663,7 +4663,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) ext4_orphan_del(NULL, inode); if (!rc && (ia_valid & ATTR_MODE)) - rc = ext4_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); err_out: ext4_std_error(inode->i_sb, error); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 5a0408d..e77c1ba 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3225,6 +3225,7 @@ const struct inode_operations ext4_dir_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, }; @@ -3235,4 +3236,5 @@ const struct inode_operations ext4_special_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, }; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 1423c48..e175e94 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -95,8 +95,8 @@ static struct mb_cache *ext4_xattr_cache; static const struct xattr_handler *ext4_xattr_handler_map[] = { [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, #ifdef CONFIG_EXT4_FS_POSIX_ACL - [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler, - [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, #ifdef CONFIG_EXT4_FS_SECURITY @@ -108,8 +108,8 @@ const struct xattr_handler *ext4_xattr_handlers[] = { &ext4_xattr_user_handler, &ext4_xattr_trusted_handler, #ifdef CONFIG_EXT4_FS_POSIX_ACL - &ext4_xattr_acl_access_handler, - &ext4_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT4_FS_SECURITY &ext4_xattr_security_handler, diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index c767dbd..819d639 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -96,8 +96,6 @@ struct ext4_xattr_ibody_find { extern const struct xattr_handler ext4_xattr_user_handler; extern const struct xattr_handler ext4_xattr_trusted_handler; -extern const struct xattr_handler ext4_xattr_acl_access_handler; -extern const struct xattr_handler ext4_xattr_acl_default_handler; extern const struct xattr_handler ext4_xattr_security_handler; extern ssize_t ext4_listxattr(struct dentry *, char *, size_t); -- cgit v0.10.2 From a6dda0e63e97122ce9e0ba04367e37cca28315fa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:45 -0800 Subject: f2fs: use generic posix ACL infrastructure f2fs has some weird mode bit handling, so still using the old chmod code for now. Signed-off-by: Christoph Hellwig Reviewed-by: Jaegeuk Kim Signed-off-by: Al Viro diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 45e8430..fa8da4c 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -17,9 +17,6 @@ #include "xattr.h" #include "acl.h" -#define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ - (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) - static inline size_t f2fs_acl_size(int count) { if (count <= 4) { @@ -167,19 +164,11 @@ fail: 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; @@ -205,21 +194,15 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type) return acl; } -static int f2fs_set_acl(struct inode *inode, int type, +static int __f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl, struct page *ipage) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); int name_index; void *value = NULL; size_t size = 0; int error; - if (!test_opt(sbi, POSIX_ACL)) - return 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -261,154 +244,31 @@ static int f2fs_set_acl(struct inode *inode, int type, return error; } -int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) +int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(sbi, POSIX_ACL)) { - acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - - if (!test_opt(sbi, POSIX_ACL) || !acl) - goto cleanup; - - if (S_ISDIR(inode->i_mode)) { - error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage); - if (error) - goto cleanup; - } - error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); -cleanup: - posix_acl_release(acl); - return error; + return __f2fs_set_acl(inode, type, acl, NULL); } -int f2fs_acl_chmod(struct inode *inode) +int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct posix_acl *acl; - int error; - umode_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); + struct posix_acl *default_acl, *acl; + int error = 0; - error = __posix_acl_chmod(&acl, GFP_KERNEL, mode); + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL); - posix_acl_release(acl); - return error; -} - -static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - const char *xname = POSIX_ACL_XATTR_DEFAULT; - size_t size; - - if (!test_opt(sbi, POSIX_ACL)) - return 0; - - if (type == ACL_TYPE_ACCESS) - xname = POSIX_ACL_XATTR_ACCESS; - - size = strlen(xname) + 1; - if (list && size <= list_size) - memcpy(list, xname, size); - return size; -} - -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 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 (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(sbi, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, 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; + if (default_acl) { + error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, + ipage); + posix_acl_release(default_acl); + } + if (acl) { + if (error) + error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, + ipage); + posix_acl_release(acl); } - error = f2fs_set_acl(inode, type, acl, NULL); - -release_and_out: - posix_acl_release(acl); return error; } - -const struct xattr_handler f2fs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = f2fs_xattr_list_acl, - .get = f2fs_xattr_get_acl, - .set = f2fs_xattr_set_acl, -}; - -const struct xattr_handler f2fs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = f2fs_xattr_list_acl, - .get = f2fs_xattr_get_acl, - .set = f2fs_xattr_set_acl, -}; diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index 4963313..e086465 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -37,18 +37,13 @@ struct f2fs_acl_header { #ifdef CONFIG_F2FS_FS_POSIX_ACL extern struct posix_acl *f2fs_get_acl(struct inode *, int); -extern int f2fs_acl_chmod(struct inode *); +extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int f2fs_init_acl(struct inode *, struct inode *, struct page *); #else #define f2fs_check_acl NULL #define f2fs_get_acl NULL #define f2fs_set_acl NULL -static inline int f2fs_acl_chmod(struct inode *inode) -{ - return 0; -} - static inline int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *page) { diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 89dc750..934b59c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -953,6 +953,10 @@ static inline int f2fs_readonly(struct super_block *sb) return sb->s_flags & MS_RDONLY; } +#define get_inode_mode(i) \ + ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ + (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) + /* * file.c */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7d714f4..cf835e0 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -390,7 +390,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) __setattr_copy(inode, attr); if (attr->ia_valid & ATTR_MODE) { - err = f2fs_acl_chmod(inode); + err = posix_acl_chmod(inode, get_inode_mode(inode)); if (err || is_inode_flag_set(fi, FI_ACL_MODE)) { inode->i_mode = fi->i_acl_mode; clear_inode_flag(fi, FI_ACL_MODE); @@ -405,6 +405,7 @@ const struct inode_operations f2fs_file_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 575adac..5846eeb 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -496,6 +496,7 @@ const struct inode_operations f2fs_dir_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, @@ -522,6 +523,7 @@ const struct inode_operations f2fs_special_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index aa7a3f1..e2b9299 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "f2fs.h" #include "xattr.h" @@ -216,8 +217,8 @@ const struct xattr_handler f2fs_xattr_security_handler = { static const struct xattr_handler *f2fs_xattr_handler_map[] = { [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL - [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler, - [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, + [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, #ifdef CONFIG_F2FS_FS_SECURITY @@ -229,8 +230,8 @@ static const struct xattr_handler *f2fs_xattr_handler_map[] = { const struct xattr_handler *f2fs_xattr_handlers[] = { &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL - &f2fs_xattr_acl_access_handler, - &f2fs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &f2fs_xattr_trusted_handler, #ifdef CONFIG_F2FS_FS_SECURITY diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 02a08fb..b21d9eb 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -108,8 +108,6 @@ struct f2fs_xattr_entry { #ifdef CONFIG_F2FS_FS_XATTR extern const struct xattr_handler f2fs_xattr_user_handler; extern const struct xattr_handler f2fs_xattr_trusted_handler; -extern const struct xattr_handler f2fs_xattr_acl_access_handler; -extern const struct xattr_handler f2fs_xattr_acl_default_handler; extern const struct xattr_handler f2fs_xattr_advise_handler; extern const struct xattr_handler f2fs_xattr_security_handler; -- cgit v0.10.2 From b0a7ab5706647844e7a1b91b0c31cdb3bee1e1cc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:46 -0800 Subject: hfsplus: use generic posix ACL infrastructure Signed-off-by: Christoph Hellwig Reviewed-by: Vyacheslav Dubeyko Signed-off-by: Al Viro diff --git a/fs/hfsplus/acl.h b/fs/hfsplus/acl.h index 07c0d49..95c8ed9 100644 --- a/fs/hfsplus/acl.h +++ b/fs/hfsplus/acl.h @@ -12,16 +12,13 @@ /* posix_acl.c */ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type); -extern int hfsplus_posix_acl_chmod(struct inode *); +int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, + int type); extern int hfsplus_init_posix_acl(struct inode *, struct inode *); #else /* CONFIG_HFSPLUS_FS_POSIX_ACL */ #define hfsplus_get_posix_acl NULL - -static inline int hfsplus_posix_acl_chmod(struct inode *inode) -{ - return 0; -} +#define hfsplus_set_posix_acl NULL static inline int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) { diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 4a4fea0..9ee6298 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -532,6 +532,7 @@ const struct inode_operations hfsplus_dir_inode_operations = { .removexattr = hfsplus_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, + .set_acl = hfsplus_set_posix_acl, #endif }; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 37213d0..2e10993 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -319,7 +319,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) mark_inode_dirty(inode); if (attr->ia_valid & ATTR_MODE) { - error = hfsplus_posix_acl_chmod(inode); + error = posix_acl_chmod(inode, inode->i_mode); if (unlikely(error)) return error; } @@ -393,6 +393,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { .removexattr = hfsplus_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, + .set_acl = hfsplus_set_posix_acl, #endif }; diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c index 277942f..df0c9af 100644 --- a/fs/hfsplus/posix_acl.c +++ b/fs/hfsplus/posix_acl.c @@ -17,9 +17,7 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) char *value = NULL; ssize_t size; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; + hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); switch (type) { case ACL_TYPE_ACCESS: @@ -56,17 +54,15 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) return acl; } -static int hfsplus_set_posix_acl(struct inode *inode, - int type, - struct posix_acl *acl) +int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, + int type) { int err; char *xattr_name; size_t size = 0; char *value = NULL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; + hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); switch (type) { case ACL_TYPE_ACCESS: @@ -115,7 +111,7 @@ end_set_acl: int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) { int err = 0; - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; hfs_dbg(ACL_MOD, "[%s]: ino %lu, dir->ino %lu\n", @@ -124,151 +120,21 @@ int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) if (S_ISLNK(inode->i_mode)) return 0; - acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (acl) { - if (S_ISDIR(inode->i_mode)) { - err = hfsplus_set_posix_acl(inode, - ACL_TYPE_DEFAULT, - acl); - if (unlikely(err)) - goto init_acl_cleanup; - } - - err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (unlikely(err < 0)) - return err; - - if (err > 0) - err = hfsplus_set_posix_acl(inode, - ACL_TYPE_ACCESS, - acl); - } else - inode->i_mode &= ~current_umask(); - -init_acl_cleanup: - posix_acl_release(acl); - return err; -} - -int hfsplus_posix_acl_chmod(struct inode *inode) -{ - int err; - struct posix_acl *acl; - - hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - err = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (unlikely(err)) + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (err) return err; - err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return err; -} - -static int hfsplus_xattr_get_posix_acl(struct dentry *dentry, - const char *name, - void *buffer, - size_t size, - int type) -{ - int err = 0; - struct posix_acl *acl; - - hfs_dbg(ACL_MOD, - "[%s]: ino %lu, buffer %p, size %zu, type %#x\n", - __func__, dentry->d_inode->i_ino, buffer, size, type); - - if (strcmp(name, "") != 0) - return -EINVAL; - - acl = hfsplus_get_posix_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return err; -} - -static int hfsplus_xattr_set_posix_acl(struct dentry *dentry, - const char *name, - const void *value, - size_t size, - int flags, - int type) -{ - int err = 0; - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; - - hfs_dbg(ACL_MOD, - "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n", - __func__, inode->i_ino, value, size, flags, type); - - if (strcmp(name, "") != 0) - return -EINVAL; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - err = posix_acl_valid(acl); - if (err) - goto end_xattr_set_acl; - } + if (default_acl) { + err = hfsplus_set_posix_acl(inode, default_acl, + ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); } - err = hfsplus_set_posix_acl(inode, type, acl); - -end_xattr_set_acl: - posix_acl_release(acl); + if (acl) { + if (!err) + err = hfsplus_set_posix_acl(inode, acl, + ACL_TYPE_ACCESS); + posix_acl_release(acl); + } return err; } - -static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry, - char *list, - size_t list_size, - const char *name, - size_t name_len, - int type) -{ - /* - * This method is not used. - * It is used hfsplus_listxattr() instead of generic_listxattr(). - */ - return -EOPNOTSUPP; -} - -const struct xattr_handler hfsplus_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = hfsplus_xattr_list_posix_acl, - .get = hfsplus_xattr_get_posix_acl, - .set = hfsplus_xattr_set_posix_acl, -}; - -const struct xattr_handler hfsplus_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = hfsplus_xattr_list_posix_acl, - .get = hfsplus_xattr_get_posix_acl, - .set = hfsplus_xattr_set_posix_acl, -}; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index 3c6136f..bf88baa 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -7,6 +7,7 @@ */ #include "hfsplus_fs.h" +#include #include "xattr.h" #include "acl.h" @@ -15,8 +16,8 @@ const struct xattr_handler *hfsplus_xattr_handlers[] = { &hfsplus_xattr_user_handler, &hfsplus_xattr_trusted_handler, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL - &hfsplus_xattr_acl_access_handler, - &hfsplus_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &hfsplus_xattr_security_handler, NULL diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 841b569..9e21449 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -14,8 +14,6 @@ extern const struct xattr_handler hfsplus_xattr_osx_handler; extern const struct xattr_handler hfsplus_xattr_user_handler; extern const struct xattr_handler hfsplus_xattr_trusted_handler; -extern const struct xattr_handler hfsplus_xattr_acl_access_handler; -extern const struct xattr_handler hfsplus_xattr_acl_default_handler; extern const struct xattr_handler hfsplus_xattr_security_handler; extern const struct xattr_handler *hfsplus_xattr_handlers[]; -- cgit v0.10.2 From f2963d4551e7f500025d687586a25a09ea28941e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:47 -0800 Subject: jffs2: use generic posix ACL infrastructure Also don't bother to set up a .get_acl method for symlinks as we do not support access control (ACLs or even mode bits) for symlinks in Linux. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 4d6e31b..009ec0b 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -178,10 +178,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type) char *value = NULL; int rc, xprefix; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; @@ -232,13 +228,10 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a return rc; } -static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int rc, xprefix; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; @@ -277,30 +270,21 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int rc; cache_no_acl(inode); - if (S_ISLNK(*i_mode)) - return 0; /* Symlink always has no-ACL */ - - acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (!acl) { - *i_mode &= ~current_umask(); - } else { - if (S_ISDIR(*i_mode)) - set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - - rc = __posix_acl_create(&acl, GFP_KERNEL, i_mode); - if (rc < 0) - return rc; - if (rc > 0) - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl); + if (rc) + return rc; + if (default_acl) { + set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); + posix_acl_release(default_acl); + } + if (acl) { + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return 0; @@ -324,106 +308,3 @@ int jffs2_init_acl_post(struct inode *inode) return 0; } - -int jffs2_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int rc; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (rc) - return rc; - rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return rc; -} - -static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (list && retlen <= list_size) - strcpy(list, POSIX_ACL_XATTR_ACCESS); - return retlen; -} - -static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (list && retlen <= list_size) - strcpy(list, POSIX_ACL_XATTR_DEFAULT); - return retlen; -} - -static int jffs2_acl_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct posix_acl *acl; - int rc; - - if (name[0] != '\0') - return -EINVAL; - - acl = jffs2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - return -ENODATA; - rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return rc; -} - -static int jffs2_acl_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct posix_acl *acl; - int rc; - - if (name[0] != '\0') - return -EINVAL; - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - rc = posix_acl_valid(acl); - if (rc) - goto out; - } - } else { - acl = NULL; - } - rc = jffs2_set_acl(dentry->d_inode, type, acl); - out: - posix_acl_release(acl); - return rc; -} - -const struct xattr_handler jffs2_acl_access_xattr_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_DEFAULT, - .list = jffs2_acl_access_listxattr, - .get = jffs2_acl_getxattr, - .set = jffs2_acl_setxattr, -}; - -const struct xattr_handler jffs2_acl_default_xattr_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = jffs2_acl_default_listxattr, - .get = jffs2_acl_getxattr, - .set = jffs2_acl_setxattr, -}; diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 9b47724..2e2b574 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -27,17 +27,14 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL struct posix_acl *jffs2_get_acl(struct inode *inode, int type); -extern int jffs2_acl_chmod(struct inode *); +int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *); extern int jffs2_init_acl_post(struct inode *); -extern const struct xattr_handler jffs2_acl_access_xattr_handler; -extern const struct xattr_handler jffs2_acl_default_xattr_handler; - #else #define jffs2_get_acl (NULL) -#define jffs2_acl_chmod(inode) (0) +#define jffs2_set_acl (NULL) #define jffs2_init_acl_pre(dir_i,inode,mode) (0) #define jffs2_init_acl_post(inode) (0) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index e3aac22..9385560 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -59,6 +59,7 @@ const struct inode_operations jffs2_dir_inode_operations = .mknod = jffs2_mknod, .rename = jffs2_rename, .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 1506673..256cd19 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -66,6 +66,7 @@ const struct file_operations jffs2_file_operations = const struct inode_operations jffs2_file_inode_operations = { .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 09b3ed4..a69e426 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -190,15 +190,16 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) { + struct inode *inode = dentry->d_inode; int rc; - rc = inode_change_ok(dentry->d_inode, iattr); + rc = inode_change_ok(inode, iattr); if (rc) return rc; - rc = jffs2_do_setattr(dentry->d_inode, iattr); + rc = jffs2_do_setattr(inode, iattr); if (!rc && (iattr->ia_valid & ATTR_MODE)) - rc = jffs2_acl_chmod(dentry->d_inode); + rc = posix_acl_chmod(inode, inode->i_mode); return rc; } diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 6e56333..c7c77b0 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -22,7 +22,6 @@ const struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, - .get_acl = jffs2_get_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 3034e97..ad0f2e2 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "nodelist.h" /* -------- xdatum related functions ---------------- @@ -921,8 +922,8 @@ const struct xattr_handler *jffs2_xattr_handlers[] = { &jffs2_security_xattr_handler, #endif #ifdef CONFIG_JFFS2_FS_POSIX_ACL - &jffs2_acl_access_xattr_handler, - &jffs2_acl_default_xattr_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &jffs2_trusted_xattr_handler, NULL @@ -942,10 +943,10 @@ static const struct xattr_handler *xprefix_to_handler(int xprefix) { #endif #ifdef CONFIG_JFFS2_FS_POSIX_ACL case JFFS2_XPREFIX_ACL_ACCESS: - ret = &jffs2_acl_access_xattr_handler; + ret = &posix_acl_access_xattr_handler; break; case JFFS2_XPREFIX_ACL_DEFAULT: - ret = &jffs2_acl_default_xattr_handler; + ret = &posix_acl_default_xattr_handler; break; #endif case JFFS2_XPREFIX_TRUSTED: -- cgit v0.10.2 From 702e5bc68ad2c02f1b12b53ef7093074af9d2441 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:48 -0800 Subject: ocfs2: use generic posix ACL infrastructure This contains some major refactoring for the create path so that inodes are created with the right mode to start with instead of fixing it up later. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index c0f9d2f..555f4cd 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -160,36 +160,6 @@ static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, return acl; } - -/* - * Get posix acl. - */ -static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct buffer_head *di_bh = NULL; - struct posix_acl *acl; - int ret; - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return NULL; - - ret = ocfs2_inode_lock(inode, &di_bh, 0); - if (ret < 0) { - mlog_errno(ret); - acl = ERR_PTR(ret); - return acl; - } - - acl = ocfs2_get_acl_nolock(inode, type, di_bh); - - ocfs2_inode_unlock(inode, 0); - - brelse(di_bh); - - return acl; -} - /* * Helper function to set i_mode in memory and disk. Some call paths * will not have di_bh or a journal handle to pass, in which case it @@ -250,7 +220,7 @@ out: /* * Set the access or default ACL of an inode. */ -static int ocfs2_set_acl(handle_t *handle, +int ocfs2_set_acl(handle_t *handle, struct inode *inode, struct buffer_head *di_bh, int type, @@ -313,6 +283,11 @@ static int ocfs2_set_acl(handle_t *handle, return ret; } +int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); +} + struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) { struct ocfs2_super *osb; @@ -334,200 +309,3 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) return acl; } - -int ocfs2_acl_chmod(struct inode *inode) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl; - int ret; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (ret) - return ret; - ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, - acl, NULL, NULL); - posix_acl_release(acl); - return ret; -} - -/* - * Initialize the ACLs of a new inode. If parent directory has default ACL, - * then clone to new inode. Called from ocfs2_mknod. - */ -int ocfs2_init_acl(handle_t *handle, - struct inode *inode, - struct inode *dir, - struct buffer_head *di_bh, - struct buffer_head *dir_bh, - struct ocfs2_alloc_context *meta_ac, - struct ocfs2_alloc_context *data_ac) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl = NULL; - int ret = 0, ret2; - umode_t mode; - - if (!S_ISLNK(inode->i_mode)) { - if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { - acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, - dir_bh); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) { - mode = inode->i_mode & ~current_umask(); - ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret) { - mlog_errno(ret); - goto cleanup; - } - } - } - if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - ret = ocfs2_set_acl(handle, inode, di_bh, - ACL_TYPE_DEFAULT, acl, - meta_ac, data_ac); - if (ret) - goto cleanup; - } - mode = inode->i_mode; - ret = __posix_acl_create(&acl, GFP_NOFS, &mode); - if (ret < 0) - return ret; - - ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret2) { - mlog_errno(ret2); - ret = ret2; - goto cleanup; - } - if (ret > 0) { - ret = ocfs2_set_acl(handle, inode, - di_bh, ACL_TYPE_ACCESS, - acl, meta_ac, data_ac); - } - } -cleanup: - posix_acl_release(acl); - return ret; -} - -static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, - char *list, - size_t list_len, - const char *name, - size_t name_len, - int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, - char *list, - size_t list_len, - const char *name, - size_t name_len, - int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - struct posix_acl *acl; - int ret; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ocfs2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return ret; -} - -static int ocfs2_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; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl; - int ret = 0; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return -EOPNOTSUPP; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - ret = posix_acl_valid(acl); - if (ret) - goto cleanup; - } - } else - acl = NULL; - - ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); - -cleanup: - posix_acl_release(acl); - return ret; -} - -const struct xattr_handler ocfs2_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ocfs2_xattr_list_acl_access, - .get = ocfs2_xattr_get_acl, - .set = ocfs2_xattr_set_acl, -}; - -const struct xattr_handler ocfs2_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ocfs2_xattr_list_acl_default, - .get = ocfs2_xattr_get_acl, - .set = ocfs2_xattr_set_acl, -}; diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h index 071fbd38..3fce68d 100644 --- a/fs/ocfs2/acl.h +++ b/fs/ocfs2/acl.h @@ -27,10 +27,13 @@ struct ocfs2_acl_entry { }; struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type); -extern int ocfs2_acl_chmod(struct inode *); -extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, - struct buffer_head *, struct buffer_head *, - struct ocfs2_alloc_context *, - struct ocfs2_alloc_context *); +int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type); +int ocfs2_set_acl(handle_t *handle, + struct inode *inode, + struct buffer_head *di_bh, + int type, + struct posix_acl *acl, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_alloc_context *data_ac); #endif /* OCFS2_ACL_H */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 6fff128..014a38e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1236,7 +1236,7 @@ bail: dqput(transfer_to[qtype]); if (!status && attr->ia_valid & ATTR_MODE) { - status = ocfs2_acl_chmod(inode); + status = posix_acl_chmod(inode, inode->i_mode); if (status < 0) mlog_errno(status); } @@ -2661,6 +2661,7 @@ const struct inode_operations ocfs2_file_iops = { .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; const struct inode_operations ocfs2_special_file_iops = { @@ -2668,6 +2669,7 @@ const struct inode_operations ocfs2_special_file_iops = { .getattr = ocfs2_getattr, .permission = ocfs2_permission, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; /* diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 4f791f6..c975eed 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -230,6 +230,7 @@ static int ocfs2_mknod(struct inode *dir, struct ocfs2_dir_lookup_result lookup = { NULL, }; sigset_t oldset; int did_block_signals = 0; + struct posix_acl *default_acl = NULL, *acl = NULL; trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno, @@ -331,6 +332,12 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } + status = posix_acl_create(dir, &mode, &default_acl, &acl); + if (status) { + mlog_errno(status); + goto leave; + } + handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), xattr_credits)); @@ -379,8 +386,17 @@ static int ocfs2_mknod(struct inode *dir, inc_nlink(dir); } - status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, - meta_ac, data_ac); + if (default_acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_DEFAULT, default_acl, + meta_ac, data_ac); + } + if (!status && acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_ACCESS, acl, + meta_ac, data_ac); + } + if (status < 0) { mlog_errno(status); goto leave; @@ -419,6 +435,10 @@ static int ocfs2_mknod(struct inode *dir, d_instantiate(dentry, inode); status = 0; leave: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (status < 0 && did_quota_inode) dquot_free_inode(inode); if (handle) @@ -2504,4 +2524,5 @@ const struct inode_operations ocfs2_dir_iops = { .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 55767e1..6ba4bcb 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -46,6 +46,7 @@ #include #include #include +#include struct ocfs2_cow_context { struct inode *inode; @@ -4268,11 +4269,20 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, struct inode *inode = old_dentry->d_inode; struct buffer_head *old_bh = NULL; struct inode *new_orphan_inode = NULL; + struct posix_acl *default_acl, *acl; + umode_t mode; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; - error = ocfs2_create_inode_in_orphan(dir, inode->i_mode, + mode = inode->i_mode; + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) { + mlog_errno(error); + goto out; + } + + error = ocfs2_create_inode_in_orphan(dir, mode, &new_orphan_inode); if (error) { mlog_errno(error); @@ -4303,11 +4313,16 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, /* If the security isn't preserved, we need to re-initialize them. */ if (!preserve) { error = ocfs2_init_security_and_acl(dir, new_orphan_inode, - &new_dentry->d_name); + &new_dentry->d_name, + default_acl, acl); if (error) mlog_errno(error); } out: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (!error) { error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode, new_dentry); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index f0a1326..185fa3b7 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -99,8 +99,8 @@ static struct ocfs2_xattr_def_value_root def_xv = { const struct xattr_handler *ocfs2_xattr_handlers[] = { &ocfs2_xattr_user_handler, - &ocfs2_xattr_acl_access_handler, - &ocfs2_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, &ocfs2_xattr_trusted_handler, &ocfs2_xattr_security_handler, NULL @@ -109,9 +109,9 @@ const struct xattr_handler *ocfs2_xattr_handlers[] = { static const struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS] - = &ocfs2_xattr_acl_access_handler, + = &posix_acl_access_xattr_handler, [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT] - = &ocfs2_xattr_acl_default_handler, + = &posix_acl_default_xattr_handler, [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, }; @@ -7190,10 +7190,12 @@ out: */ int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr) + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl) { - int ret = 0; struct buffer_head *dir_bh = NULL; + int ret = 0; ret = ocfs2_init_security_get(inode, dir, qstr, NULL); if (ret) { @@ -7207,9 +7209,10 @@ int ocfs2_init_security_and_acl(struct inode *dir, goto leave; } - ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL); - if (ret) - mlog_errno(ret); + if (!ret && default_acl) + ret = ocfs2_iop_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + if (!ret && acl) + ret = ocfs2_iop_set_acl(inode, acl, ACL_TYPE_ACCESS); ocfs2_inode_unlock(dir, 0); brelse(dir_bh); diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index 19f134e..f10d5b9 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h @@ -40,8 +40,6 @@ struct ocfs2_security_xattr_info { extern const struct xattr_handler ocfs2_xattr_user_handler; extern const struct xattr_handler ocfs2_xattr_trusted_handler; extern const struct xattr_handler ocfs2_xattr_security_handler; -extern const struct xattr_handler ocfs2_xattr_acl_access_handler; -extern const struct xattr_handler ocfs2_xattr_acl_default_handler; extern const struct xattr_handler *ocfs2_xattr_handlers[]; ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); @@ -96,5 +94,7 @@ int ocfs2_reflink_xattrs(struct inode *old_inode, bool preserve_security); int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr); + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl); #endif /* OCFS2_XATTR_H */ -- cgit v0.10.2 From 47f70d08facf288a9faad6e6c36ac2e670be8195 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:49 -0800 Subject: reiserfs: use generic posix ACL infrastructure Also don't bother to set up a .get_acl method for symlinks as we do not support access control (ACLs or even mode bits) for symlinks in Linux. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/reiserfs/acl.h b/fs/reiserfs/acl.h index f096b80..4a211f5 100644 --- a/fs/reiserfs/acl.h +++ b/fs/reiserfs/acl.h @@ -48,18 +48,18 @@ static inline int reiserfs_acl_count(size_t size) #ifdef CONFIG_REISERFS_FS_POSIX_ACL struct posix_acl *reiserfs_get_acl(struct inode *inode, int type); +int reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int reiserfs_acl_chmod(struct inode *inode); int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode); int reiserfs_cache_default_acl(struct inode *dir); -extern const struct xattr_handler reiserfs_posix_acl_default_handler; -extern const struct xattr_handler reiserfs_posix_acl_access_handler; #else #define reiserfs_cache_default_acl(inode) 0 #define reiserfs_get_acl NULL +#define reiserfs_set_acl NULL static inline int reiserfs_acl_chmod(struct inode *inode) { diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index dcaafcf..ed58d84 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -260,4 +260,5 @@ const struct inode_operations reiserfs_file_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index dc5236f..e825f8b 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1522,6 +1522,7 @@ const struct inode_operations reiserfs_dir_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; /* @@ -1538,8 +1539,6 @@ const struct inode_operations reiserfs_symlink_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .get_acl = reiserfs_get_acl, - }; /* @@ -1553,4 +1552,5 @@ const struct inode_operations reiserfs_special_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 8a9e2dc..5cdfbd6 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -50,6 +50,7 @@ #include #include #include +#include #define PRIVROOT_NAME ".reiserfs_priv" #define XAROOT_NAME "xattrs" @@ -904,8 +905,8 @@ static const struct xattr_handler *reiserfs_xattr_handlers[] = { &reiserfs_xattr_security_handler, #endif #ifdef CONFIG_REISERFS_FS_POSIX_ACL - &reiserfs_posix_acl_access_handler, - &reiserfs_posix_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index d95c959..a6ce532 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -11,35 +11,19 @@ #include "acl.h" #include -static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, +static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, int type, struct posix_acl *acl); -static int -reiserfs_posix_acl_set(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) + +int +reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; int error, error2; struct reiserfs_transaction_handle th; size_t jcreate_blocks; - if (!reiserfs_posixacl(inode->i_sb)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, 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; + int size = acl ? posix_acl_xattr_size(acl->a_count) : 0; + /* Pessimism: We can't assume that anything from the xattr root up * has been created. */ @@ -51,7 +35,7 @@ reiserfs_posix_acl_set(struct dentry *dentry, const char *name, const void *valu error = journal_begin(&th, inode->i_sb, jcreate_blocks); reiserfs_write_unlock(inode->i_sb); if (error == 0) { - error = reiserfs_set_acl(&th, inode, type, acl); + error = __reiserfs_set_acl(&th, inode, type, acl); reiserfs_write_lock(inode->i_sb); error2 = journal_end(&th, inode->i_sb, jcreate_blocks); reiserfs_write_unlock(inode->i_sb); @@ -59,29 +43,6 @@ reiserfs_posix_acl_set(struct dentry *dentry, const char *name, const void *valu error = error2; } - release_and_out: - posix_acl_release(acl); - return error; -} - -static int -reiserfs_posix_acl_get(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - struct posix_acl *acl; - int error; - - if (!reiserfs_posixacl(dentry->d_sb)) - return -EOPNOTSUPP; - - acl = reiserfs_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - return error; } @@ -221,10 +182,6 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) int size; int retval; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -273,7 +230,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) * BKL held [before 2.5.x] */ static int -reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, +__reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, int type, struct posix_acl *acl) { char *name; @@ -281,9 +238,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -343,7 +297,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int err = 0; /* ACLs only get applied to files and directories */ @@ -363,37 +317,28 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, goto apply_umask; } - acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (err) + return err; + if (default_acl) { + err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } if (acl) { - /* Copy the default ACL to the default ACL of a new directory */ - if (S_ISDIR(inode->i_mode)) { - err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, - acl); - if (err) - goto cleanup; - } - - /* Now we reconcile the new ACL and the mode, - potentially modifying both */ - err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (err < 0) - return err; - - /* If we need an ACL.. */ - if (err > 0) - err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl); - cleanup: + if (!err) + err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, + acl); posix_acl_release(acl); - } else { - apply_umask: - /* no ACL, apply umask */ - inode->i_mode &= ~current_umask(); } return err; + + apply_umask: + /* no ACL, apply umask */ + inode->i_mode &= ~current_umask(); + return err; } /* This is used to cache the default acl before a new object is created. @@ -442,84 +387,11 @@ int reiserfs_cache_default_acl(struct inode *inode) */ int reiserfs_acl_chmod(struct inode *inode) { - struct reiserfs_transaction_handle th; - struct posix_acl *acl; - size_t size; - int error; - if (IS_PRIVATE(inode)) return 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (get_inode_sd_version(inode) == STAT_DATA_V1 || - !reiserfs_posixacl(inode->i_sb)) { + !reiserfs_posixacl(inode->i_sb)) return 0; - } - acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); - if (!acl) - return 0; - if (IS_ERR(acl)) - return PTR_ERR(acl); - error = __posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode); - if (error) - return error; - - size = reiserfs_xattr_nblocks(inode, reiserfs_acl_size(acl->a_count)); - reiserfs_write_lock(inode->i_sb); - error = journal_begin(&th, inode->i_sb, size * 2); - reiserfs_write_unlock(inode->i_sb); - if (!error) { - int error2; - error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, acl); - reiserfs_write_lock(inode->i_sb); - error2 = journal_end(&th, inode->i_sb, size * 2); - reiserfs_write_unlock(inode->i_sb); - if (error2) - error = error2; - } - posix_acl_release(acl); - return error; -} - -static size_t posix_acl_access_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, - size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - if (!reiserfs_posixacl(dentry->d_sb)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; + return posix_acl_chmod(inode, inode->i_mode); } - -const struct xattr_handler reiserfs_posix_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = reiserfs_posix_acl_get, - .set = reiserfs_posix_acl_set, - .list = posix_acl_access_list, -}; - -static size_t posix_acl_default_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, - size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - if (!reiserfs_posixacl(dentry->d_sb)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -const struct xattr_handler reiserfs_posix_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = reiserfs_posix_acl_get, - .set = reiserfs_posix_acl_set, - .list = posix_acl_default_list, -}; -- cgit v0.10.2 From 2401dc2975fc5a33021dc8347ea82984c4707a08 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:50 -0800 Subject: xfs: use generic posix ACL infrastructure Also don't bother to set up a .get_acl method for symlinks as we do not support access control (ACLs or even mode bits) for symlinks in Linux, and create inodes with the proper mode instead of fixing it up later. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Al Viro diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 057ae2d..0ecec18 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -124,16 +124,12 @@ struct posix_acl * xfs_get_acl(struct inode *inode, int type) { struct xfs_inode *ip = XFS_I(inode); - struct posix_acl *acl; + struct posix_acl *acl = NULL; struct xfs_acl *xfs_acl; unsigned char *ea_name; int error; int len; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - trace_xfs_get_acl(ip); switch (type) { @@ -164,10 +160,8 @@ xfs_get_acl(struct inode *inode, int type) * cache entry, for any other error assume it is transient and * leave the cache entry as ACL_NOT_CACHED. */ - if (error == -ENOATTR) { - acl = NULL; + if (error == -ENOATTR) goto out_update_cache; - } goto out; } @@ -183,15 +177,12 @@ out: } STATIC int -xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct xfs_inode *ip = XFS_I(inode); unsigned char *ea_name; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; @@ -282,131 +273,23 @@ posix_acl_default_exists(struct inode *inode) return xfs_acl_exists(inode, SGI_ACL_DEFAULT); } -/* - * No need for i_mutex because the inode is not yet exposed to the VFS. - */ int -xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) +xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - umode_t mode = inode->i_mode; - int error = 0, inherit = 0; - - if (S_ISDIR(inode->i_mode)) { - error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto out; - } - - error = __posix_acl_create(&acl, GFP_KERNEL, &mode); - if (error < 0) - return error; - - /* - * If __posix_acl_create returns a positive value we need to - * inherit a permission that can't be represented using the Unix - * mode bits and we actually need to set an ACL. - */ - if (error > 0) - inherit = 1; - - error = xfs_set_mode(inode, mode); - if (error) - goto out; - - if (inherit) - error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); - -out: - posix_acl_release(acl); - return error; -} - -int -xfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = xfs_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 = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return error; -} - -static int -xfs_xattr_acl_get(struct dentry *dentry, const char *name, - void *value, size_t size, int type) -{ - struct posix_acl *acl; - int error; - - acl = xfs_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - error = posix_acl_to_xattr(&init_user_ns, acl, value, size); - posix_acl_release(acl); - - return error; -} - -static int -xfs_xattr_acl_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; int error = 0; - if (flags & XATTR_CREATE) - return -EINVAL; - if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) - return value ? -EACCES : 0; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (!value) + if (!acl) goto set_acl; - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (!acl) { - /* - * acl_set_file(3) may request that we set default ACLs with - * zero length -- defend (gracefully) against that here. - */ - goto out; - } - if (IS_ERR(acl)) { - error = PTR_ERR(acl); - goto out; - } - - error = posix_acl_valid(acl); - if (error) - goto out_release; - error = -EINVAL; if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) - goto out_release; + return error; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { - posix_acl_release(acl); acl = NULL; if (error < 0) @@ -415,27 +298,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name, error = xfs_set_mode(inode, mode); if (error) - goto out_release; + return error; } set_acl: - error = xfs_set_acl(inode, type, acl); - out_release: - posix_acl_release(acl); - out: - return error; + return __xfs_set_acl(inode, type, acl); } - -const struct xattr_handler xfs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = xfs_xattr_acl_get, - .set = xfs_xattr_acl_set, -}; - -const struct xattr_handler xfs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = xfs_xattr_acl_get, - .set = xfs_xattr_acl_set, -}; diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 4016a56..5dc1637 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -60,20 +60,15 @@ struct xfs_acl { #ifdef CONFIG_XFS_POSIX_ACL extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); -extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); -extern int xfs_acl_chmod(struct inode *inode); +extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int posix_acl_access_exists(struct inode *inode); extern int posix_acl_default_exists(struct inode *inode); - -extern const struct xattr_handler xfs_xattr_acl_access_handler; -extern const struct xattr_handler xfs_xattr_acl_default_handler; #else static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) { return NULL; } -# define xfs_inherit_acl(inode, default_acl) 0 -# define xfs_acl_chmod(inode) 0 +# define xfs_set_acl NULL # define posix_acl_access_exists(inode) 0 # define posix_acl_default_exists(inode) 0 #endif /* CONFIG_XFS_POSIX_ACL */ diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index a3dad17..d47fbee 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -123,7 +123,7 @@ xfs_vn_mknod( { struct inode *inode; struct xfs_inode *ip = NULL; - struct posix_acl *default_acl = NULL; + struct posix_acl *default_acl, *acl; struct xfs_name name; int error; @@ -139,14 +139,9 @@ xfs_vn_mknod( rdev = 0; } - if (IS_POSIXACL(dir)) { - default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(default_acl)) - return PTR_ERR(default_acl); - - if (!default_acl) - mode &= ~current_umask(); - } + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) + return error; xfs_dentry_to_name(&name, dentry, mode); error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); @@ -159,22 +154,30 @@ xfs_vn_mknod( if (unlikely(error)) goto out_cleanup_inode; +#ifdef CONFIG_XFS_POSIX_ACL if (default_acl) { - error = -xfs_inherit_acl(inode, default_acl); - default_acl = NULL; - if (unlikely(error)) + error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + if (error) goto out_cleanup_inode; } - + if (acl) { + error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); + if (error) + goto out_cleanup_inode; + } +#endif d_instantiate(dentry, inode); + out_free_acl: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); return -error; out_cleanup_inode: xfs_cleanup_inode(dir, inode, dentry); - out_free_acl: - posix_acl_release(default_acl); - return -error; + goto out_free_acl; } STATIC int @@ -672,7 +675,7 @@ xfs_setattr_nonsize( * Posix ACL code seems to care about this issue either. */ if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { - error = -xfs_acl_chmod(inode); + error = -posix_acl_chmod(inode, inode->i_mode); if (error) return XFS_ERROR(error); } @@ -1041,6 +1044,7 @@ xfs_vn_fiemap( static const struct inode_operations xfs_inode_operations = { .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1068,6 +1072,7 @@ static const struct inode_operations xfs_dir_inode_operations = { .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1094,6 +1099,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1107,7 +1113,6 @@ static const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, .put_link = kfree_put_link, - .get_acl = xfs_get_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h index d2c5057..1c34e43 100644 --- a/fs/xfs/xfs_iops.h +++ b/fs/xfs/xfs_iops.h @@ -30,7 +30,7 @@ extern void xfs_setup_inode(struct xfs_inode *); /* * Internal setattr interfaces. */ -#define XFS_ATTR_NOACL 0x01 /* Don't call xfs_acl_chmod */ +#define XFS_ATTR_NOACL 0x01 /* Don't call posix_acl_chmod */ extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags); diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 9d47907..78ed92a 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -102,8 +102,8 @@ const struct xattr_handler *xfs_xattr_handlers[] = { &xfs_xattr_trusted_handler, &xfs_xattr_security_handler, #ifdef CONFIG_XFS_POSIX_ACL - &xfs_xattr_acl_access_handler, - &xfs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; -- cgit v0.10.2 From 2cc6a5a01cdbeb0e46f3aa144819d5d7cee458a1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:51 -0800 Subject: jfs: use generic posix ACL infrastructure Copy the scheme I introduced to btrfs many years ago to only use the xattr handler for ACLs, but pass plain attrs straight through. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Kleikamp Signed-off-by: Al Viro diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 28d529a..e973b85 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -72,7 +72,7 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type) return acl; } -static int jfs_set_acl(tid_t tid, struct inode *inode, int type, +static int __jfs_set_acl(tid_t tid, struct inode *inode, int type, struct posix_acl *acl) { char *ea_name; @@ -80,21 +80,22 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, int size = 0; char *value = NULL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - switch(type) { - case ACL_TYPE_ACCESS: - ea_name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - ea_name = POSIX_ACL_XATTR_DEFAULT; - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - break; - default: - return -EINVAL; + switch (type) { + case ACL_TYPE_ACCESS: + ea_name = POSIX_ACL_XATTR_ACCESS; + rc = posix_acl_equiv_mode(acl, &inode->i_mode); + if (rc < 0) + return rc; + if (rc == 0) + acl = NULL; + break; + case ACL_TYPE_DEFAULT: + ea_name = POSIX_ACL_XATTR_DEFAULT; + break; + default: + return -EINVAL; } + if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_KERNEL); @@ -114,65 +115,43 @@ out: return rc; } +int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int rc; + tid_t tid; + + tid = txBegin(inode->i_sb, 0); + mutex_lock(&JFS_IP(inode)->commit_mutex); + rc = __jfs_set_acl(tid, inode, type, acl); + if (!rc) + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + mutex_unlock(&JFS_IP(inode)->commit_mutex); + return rc; +} + int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; int rc = 0; - if (S_ISLNK(inode->i_mode)) - return 0; + rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (rc) + return rc; - acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); + if (default_acl) { + rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); + posix_acl_release(default_acl); + } if (acl) { - if (S_ISDIR(inode->i_mode)) { - rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl); - if (rc) - goto cleanup; - } - rc = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (rc < 0) - goto cleanup; /* posix_acl_release(NULL) is no-op */ - if (rc > 0) - rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); -cleanup: + if (!rc) + rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); - } else - inode->i_mode &= ~current_umask(); + } JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | inode->i_mode; return rc; } - -int jfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int rc; - tid_t tid; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (rc) - return rc; - - tid = txBegin(inode->i_sb, 0); - mutex_lock(&JFS_IP(inode)->commit_mutex); - rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); - if (!rc) - rc = txCommit(tid, 1, &inode, 0); - txEnd(tid); - mutex_unlock(&JFS_IP(inode)->commit_mutex); - - posix_acl_release(acl); - return rc; -} diff --git a/fs/jfs/file.c b/fs/jfs/file.c index dd7442c..794da94 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "jfs_incore.h" #include "jfs_inode.h" @@ -131,7 +132,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) mark_inode_dirty(inode); if (iattr->ia_valid & ATTR_MODE) - rc = jfs_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); return rc; } @@ -143,6 +144,7 @@ const struct inode_operations jfs_file_inode_operations = { .setattr = jfs_setattr, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, + .set_acl = jfs_set_acl, #endif }; diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index ad84fe5..489f993 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -21,8 +21,8 @@ #ifdef CONFIG_JFS_POSIX_ACL struct posix_acl *jfs_get_acl(struct inode *inode, int type); +int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int jfs_init_acl(tid_t, struct inode *, struct inode *); -int jfs_acl_chmod(struct inode *inode); #else @@ -32,10 +32,5 @@ static inline int jfs_init_acl(tid_t tid, struct inode *inode, return 0; } -static inline int jfs_acl_chmod(struct inode *inode) -{ - return 0; -} - #endif #endif /* _H_JFS_ACL */ diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h index e9e100f..e8d717d 100644 --- a/fs/jfs/jfs_xattr.h +++ b/fs/jfs/jfs_xattr.h @@ -61,6 +61,8 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); extern int jfs_removexattr(struct dentry *, const char *); +extern const struct xattr_handler *jfs_xattr_handlers[]; + #ifdef CONFIG_JFS_SECURITY extern int jfs_init_security(tid_t, struct inode *, struct inode *, const struct qstr *); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index aa8a337..d59c7de 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1524,6 +1524,7 @@ const struct inode_operations jfs_dir_inode_operations = { .setattr = jfs_setattr, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, + .set_acl = jfs_set_acl, #endif }; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 6669aa2..e2b7483 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -44,6 +44,7 @@ #include "jfs_imap.h" #include "jfs_acl.h" #include "jfs_debug.h" +#include "jfs_xattr.h" MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); @@ -522,6 +523,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) */ sb->s_op = &jfs_super_operations; sb->s_export_op = &jfs_export_operations; + sb->s_xattr = jfs_xattr_handlers; #ifdef CONFIG_QUOTA sb->dq_op = &dquot_operations; sb->s_qcop = &dquot_quotactl_ops; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index d3472f4..5324e4e 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -666,81 +666,12 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf, } /* - * can_set_system_xattr - * - * This code is specific to the system.* namespace. It contains policy - * which doesn't belong in the main xattr codepath. - */ -static int can_set_system_xattr(struct inode *inode, const char *name, - const void *value, size_t value_len) -{ -#ifdef CONFIG_JFS_POSIX_ACL - struct posix_acl *acl; - int rc; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - /* - * POSIX_ACL_XATTR_ACCESS is tied to i_mode - */ - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, value_len); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - printk(KERN_ERR "posix_acl_from_xattr returned %d\n", - rc); - return rc; - } - if (acl) { - rc = posix_acl_equiv_mode(acl, &inode->i_mode); - posix_acl_release(acl); - if (rc < 0) { - printk(KERN_ERR - "posix_acl_equiv_mode returned %d\n", - rc); - return rc; - } - mark_inode_dirty(inode); - } - /* - * We're changing the ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_ACCESS); - - return 0; - } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, value_len); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - printk(KERN_ERR "posix_acl_from_xattr returned %d\n", - rc); - return rc; - } - posix_acl_release(acl); - - /* - * We're changing the default ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_DEFAULT); - - return 0; - } -#endif /* CONFIG_JFS_POSIX_ACL */ - return -EOPNOTSUPP; -} - -/* * Most of the permission checking is done by xattr_permission in the vfs. - * The local file system is responsible for handling the system.* namespace. * We also need to verify that this is a namespace that we recognize. */ static int can_set_xattr(struct inode *inode, const char *name, const void *value, size_t value_len) { - if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) - return can_set_system_xattr(inode, name, value, value_len); - if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) { /* * This makes sure that we aren't trying to set an @@ -748,7 +679,7 @@ static int can_set_xattr(struct inode *inode, const char *name, * with "os2." */ if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN)) - return -EOPNOTSUPP; + return -EOPNOTSUPP; return 0; } @@ -913,6 +844,14 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, if ((rc = can_set_xattr(inode, name, value, value_len))) return rc; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_setxattr(dentry, name, value, value_len, flags); + if (value == NULL) { /* empty EA, do not remove */ value = ""; value_len = 0; @@ -986,6 +925,14 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, { int err; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_getxattr(dentry, name, data, buf_size); + if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { /* * skip past "os2." prefix @@ -1077,6 +1024,14 @@ int jfs_removexattr(struct dentry *dentry, const char *name) if ((rc = can_set_xattr(inode, name, NULL, 0))) return rc; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_removexattr(dentry, name); + tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); @@ -1088,6 +1043,19 @@ int jfs_removexattr(struct dentry *dentry, const char *name) return rc; } +/* + * List of handlers for synthetic system.* attributes. All real ondisk + * attributes are handled directly. + */ +const struct xattr_handler *jfs_xattr_handlers[] = { +#ifdef JFS_POSIX_ACL + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, +#endif + NULL, +}; + + #ifdef CONFIG_JFS_SECURITY static int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *fs_info) -- cgit v0.10.2 From e01580bf9e4d0e3bbaead44bd46cdbfe61957732 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:52 -0800 Subject: gfs2: use generic posix ACL infrastructure This contains some major refactoring for the create path so that inodes are created with the right mode to start with instead of fixing it up later. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index e82e4ac..ba94566 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -49,10 +49,6 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type) if (!ip->i_eattr) return NULL; - acl = get_cached_acl(&ip->i_inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - name = gfs2_acl_name(type); if (name == NULL) return ERR_PTR(-EINVAL); @@ -80,7 +76,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode) return error; } -static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) +int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int error; int len; @@ -88,219 +84,49 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) const char *name = gfs2_acl_name(type); BUG_ON(name == NULL); - len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); - if (len == 0) - return 0; - data = kmalloc(len, GFP_NOFS); - if (data == NULL) - return -ENOMEM; - error = posix_acl_to_xattr(&init_user_ns, acl, data, len); - if (error < 0) - goto out; - error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); - if (!error) - set_cached_acl(inode, type, acl); -out: - kfree(data); - return error; -} - -int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct posix_acl *acl; - umode_t mode = inode->i_mode; - int error = 0; - - if (!sdp->sd_args.ar_posix_acl) - return 0; - if (S_ISLNK(inode->i_mode)) - return 0; - - acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) { - mode &= ~current_umask(); - return gfs2_set_mode(inode, mode); - } - - if (S_ISDIR(inode->i_mode)) { - error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto out; - } - - error = __posix_acl_create(&acl, GFP_NOFS, &mode); - if (error < 0) - return error; - if (error == 0) - goto munge; - - error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl); - if (error) - goto out; -munge: - error = gfs2_set_mode(inode, mode); -out: - posix_acl_release(acl); - return error; -} - -int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) -{ - struct inode *inode = &ip->i_inode; - struct posix_acl *acl; - char *data; - unsigned int len; - int error; - - acl = gfs2_get_acl(&ip->i_inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - return gfs2_setattr_simple(inode, attr); - - error = __posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode); - if (error) - return error; - - len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); - data = kmalloc(len, GFP_NOFS); - error = -ENOMEM; - if (data == NULL) - goto out; - posix_acl_to_xattr(&init_user_ns, acl, data, len); - error = gfs2_xattr_acl_chmod(ip, attr, data); - kfree(data); - set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl); - -out: - posix_acl_release(acl); - return error; -} - -static int gfs2_acl_type(const char *name) -{ - if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0) - return ACL_TYPE_ACCESS; - if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0) - return ACL_TYPE_DEFAULT; - return -EINVAL; -} - -static int gfs2_xattr_system_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int xtype) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct posix_acl *acl; - int type; - int error; - - if (!sdp->sd_args.ar_posix_acl) - return -EOPNOTSUPP; - - type = gfs2_acl_type(name); - if (type < 0) - return type; - - acl = gfs2_get_acl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, - int xtype) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct posix_acl *acl = NULL; - int error = 0, type; - - if (!sdp->sd_args.ar_posix_acl) - return -EOPNOTSUPP; - - type = gfs2_acl_type(name); - if (type < 0) - return type; - if (flags & XATTR_CREATE) - return -EINVAL; - if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) - return value ? -EACCES : 0; - if (!uid_eq(current_fsuid(), inode->i_uid) && !capable(CAP_FOWNER)) - return -EPERM; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!value) - goto set_acl; - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (!acl) { - /* - * acl_set_file(3) may request that we set default ACLs with - * zero length -- defend (gracefully) against that here. - */ - goto out; - } - if (IS_ERR(acl)) { - error = PTR_ERR(acl); - goto out; - } - - error = posix_acl_valid(acl); - if (error) - goto out_release; - - error = -EINVAL; if (acl->a_count > GFS2_ACL_MAX_ENTRIES) - goto out_release; + return -EINVAL; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + return error; - if (error <= 0) { - posix_acl_release(acl); + if (error == 0) acl = NULL; - if (error < 0) - return error; - } - error = gfs2_set_mode(inode, mode); if (error) - goto out_release; + return error; } -set_acl: - error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS); - if (!error) { - if (acl) - set_cached_acl(inode, type, acl); - else - forget_cached_acl(inode, type); + if (acl) { + len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); + if (len == 0) + return 0; + data = kmalloc(len, GFP_NOFS); + if (data == NULL) + return -ENOMEM; + error = posix_acl_to_xattr(&init_user_ns, acl, data, len); + if (error < 0) + goto out; + } else { + data = NULL; + len = 0; } -out_release: - posix_acl_release(acl); + + error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); + if (error) + goto out; + + if (acl) + set_cached_acl(inode, type, acl); + else + forget_cached_acl(inode, type); out: + kfree(data); return error; } - -const struct xattr_handler gfs2_xattr_system_handler = { - .prefix = XATTR_SYSTEM_PREFIX, - .flags = GFS2_EATYPE_SYS, - .get = gfs2_xattr_system_get, - .set = gfs2_xattr_system_set, -}; - diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 0da38dc..301260c 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -17,8 +17,6 @@ #define GFS2_ACL_MAX_ENTRIES 25 extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type); -extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); -extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); -extern const struct xattr_handler gfs2_xattr_system_handler; +extern int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); #endif /* __ACL_DOT_H__ */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7119504..d573125 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -552,6 +552,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, unsigned int size, int excl, int *opened) { const struct qstr *name = &dentry->d_name; + struct posix_acl *default_acl, *acl; struct gfs2_holder ghs[2]; struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; @@ -611,10 +612,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (!inode) goto fail_gunlock; + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) + goto fail_free_vfs_inode; + ip = GFS2_I(inode); error = gfs2_rs_alloc(ip); if (error) - goto fail_free_inode; + goto fail_free_acls; inode->i_mode = mode; set_nlink(inode, S_ISDIR(mode) ? 2 : 1); @@ -682,7 +687,16 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, gfs2_set_iop(inode); insert_inode_hash(inode); - error = gfs2_acl_create(dip, inode); + if (default_acl) { + error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + } + if (error) goto fail_gunlock3; @@ -716,6 +730,12 @@ fail_free_inode: if (ip->i_gl) gfs2_glock_put(ip->i_gl); gfs2_rs_delete(ip, NULL); +fail_free_acls: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); +fail_free_vfs_inode: free_inode_nonrcu(inode); inode = NULL; fail_gunlock: @@ -1678,10 +1698,11 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) error = gfs2_setattr_size(inode, attr->ia_size); else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) error = setattr_chown(inode, attr); - else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) - error = gfs2_acl_chmod(ip, attr); - else + else { error = gfs2_setattr_simple(inode, attr); + if (!error && attr->ia_valid & ATTR_MODE) + error = posix_acl_chmod(inode, inode->i_mode); + } out: if (!error) @@ -1841,6 +1862,7 @@ const struct inode_operations gfs2_file_iops = { .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, .get_acl = gfs2_get_acl, + .set_acl = gfs2_set_acl, }; const struct inode_operations gfs2_dir_iops = { @@ -1862,6 +1884,7 @@ const struct inode_operations gfs2_dir_iops = { .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, .get_acl = gfs2_get_acl, + .set_acl = gfs2_set_acl, .atomic_open = gfs2_atomic_open, }; @@ -1877,6 +1900,5 @@ const struct inode_operations gfs2_symlink_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .get_acl = gfs2_get_acl, }; diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 8c6a6f6..0b81f78 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -1500,7 +1501,8 @@ static const struct xattr_handler gfs2_xattr_security_handler = { const struct xattr_handler *gfs2_xattr_handlers[] = { &gfs2_xattr_user_handler, &gfs2_xattr_security_handler, - &gfs2_xattr_system_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, NULL, }; -- cgit v0.10.2 From 013cdf1088d7235da9477a2375654921d9b9ba9f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:53 -0800 Subject: nfs: use generic posix ACL infrastructure for v3 Posix ACLs This causes a small behaviour change in that we don't bother to set ACLs on file creation if the mode bit can express the access permissions fully, and thus behaving identical to local filesystems. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 00ad1c2..ecd11ba 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1641,10 +1641,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb) return NULL; nfsi->flags = 0UL; nfsi->cache_validity = 0UL; -#ifdef CONFIG_NFS_V3_ACL - nfsi->acl_access = ERR_PTR(-EAGAIN); - nfsi->acl_default = ERR_PTR(-EAGAIN); -#endif #if IS_ENABLED(CONFIG_NFS_V4) nfsi->nfs4_acl = NULL; #endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index e859675..9a5ca03 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -10,179 +10,7 @@ #define NFSDBG_FACILITY NFSDBG_PROC -ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int pos=0, len=0; - -# define output(s) do { \ - if (pos + sizeof(s) <= size) { \ - memcpy(buffer + pos, s, sizeof(s)); \ - pos += sizeof(s); \ - } \ - len += sizeof(s); \ - } while(0) - - acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - output("system.posix_acl_access"); - posix_acl_release(acl); - } - - if (S_ISDIR(inode->i_mode)) { - acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - output("system.posix_acl_default"); - posix_acl_release(acl); - } - } - -# undef output - - if (!buffer || len <= size) - return len; - return -ERANGE; -} - -ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int type, error = 0; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - acl = nfs3_proc_getacl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - if (type == ACL_TYPE_ACCESS && acl->a_count == 0) - error = -ENODATA; - else - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - } else - error = -ENODATA; - - return error; -} - -int nfs3_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int type, error; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - error = nfs3_proc_setacl(inode, type, acl); - posix_acl_release(acl); - - return error; -} - -int nfs3_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = dentry->d_inode; - int type; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - return nfs3_proc_setacl(inode, type, NULL); -} - -static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) -{ - if (!IS_ERR(nfsi->acl_access)) { - posix_acl_release(nfsi->acl_access); - nfsi->acl_access = ERR_PTR(-EAGAIN); - } - if (!IS_ERR(nfsi->acl_default)) { - posix_acl_release(nfsi->acl_default); - nfsi->acl_default = ERR_PTR(-EAGAIN); - } -} - -void nfs3_forget_cached_acls(struct inode *inode) -{ - dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, - inode->i_ino); - spin_lock(&inode->i_lock); - __nfs3_forget_cached_acls(NFS_I(inode)); - spin_unlock(&inode->i_lock); -} - -static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) -{ - struct nfs_inode *nfsi = NFS_I(inode); - struct posix_acl *acl = ERR_PTR(-EINVAL); - - spin_lock(&inode->i_lock); - switch(type) { - case ACL_TYPE_ACCESS: - acl = nfsi->acl_access; - break; - - case ACL_TYPE_DEFAULT: - acl = nfsi->acl_default; - break; - - default: - goto out; - } - if (IS_ERR(acl)) - acl = ERR_PTR(-EAGAIN); - else - acl = posix_acl_dup(acl); -out: - spin_unlock(&inode->i_lock); - dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, - inode->i_ino, type, acl); - return acl; -} - -static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, - struct posix_acl *dfacl) -{ - struct nfs_inode *nfsi = NFS_I(inode); - - dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, - inode->i_ino, acl, dfacl); - spin_lock(&inode->i_lock); - __nfs3_forget_cached_acls(NFS_I(inode)); - if (!IS_ERR(acl)) - nfsi->acl_access = posix_acl_dup(acl); - if (!IS_ERR(dfacl)) - nfsi->acl_default = posix_acl_dup(dfacl); - spin_unlock(&inode->i_lock); -} - -struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) +struct posix_acl *nfs3_get_acl(struct inode *inode, int type) { struct nfs_server *server = NFS_SERVER(inode); struct page *pages[NFSACL_MAXPAGES] = { }; @@ -198,7 +26,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) .rpc_argp = &args, .rpc_resp = &res, }; - struct posix_acl *acl; int status, count; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) @@ -207,10 +34,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); - acl = nfs3_get_cached_acl(inode, type); - if (acl != ERR_PTR(-EAGAIN)) - return acl; - acl = NULL; /* * Only get the access acl when explicitly requested: We don't @@ -257,40 +80,41 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) } if (res.acl_access != NULL) { - if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { + if (posix_acl_equiv_mode(res.acl_access, NULL) || + res.acl_access->a_count == 0) { posix_acl_release(res.acl_access); res.acl_access = NULL; } } - nfs3_cache_acls(inode, - (res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL), - (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL)); - switch(type) { - case ACL_TYPE_ACCESS: - acl = res.acl_access; - res.acl_access = NULL; - break; + if (res.mask & NFS_ACL) + set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access); + else + forget_cached_acl(inode, ACL_TYPE_ACCESS); - case ACL_TYPE_DEFAULT: - acl = res.acl_default; - res.acl_default = NULL; + if (res.mask & NFS_DFACL) + set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default); + else + forget_cached_acl(inode, ACL_TYPE_DEFAULT); + + nfs_free_fattr(res.fattr); + if (type == ACL_TYPE_ACCESS) { + posix_acl_release(res.acl_default); + return res.acl_access; + } else { + posix_acl_release(res.acl_access); + return res.acl_default; } getout: posix_acl_release(res.acl_access); posix_acl_release(res.acl_default); nfs_free_fattr(res.fattr); - - if (status != 0) { - posix_acl_release(acl); - acl = ERR_PTR(status); - } - return acl; + return ERR_PTR(status); } -static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, - struct posix_acl *dfacl) +int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_fattr *fattr; @@ -353,7 +177,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, switch (status) { case 0: status = nfs_refresh_inode(inode, fattr); - nfs3_cache_acls(inode, acl, dfacl); + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + set_cached_acl(inode, ACL_TYPE_DEFAULT, dfacl); break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: @@ -373,33 +198,27 @@ out: return status; } -int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) +int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type) { struct posix_acl *alloc = NULL, *dfacl = NULL; int status; if (S_ISDIR(inode->i_mode)) { switch(type) { - case ACL_TYPE_ACCESS: - alloc = dfacl = nfs3_proc_getacl(inode, - ACL_TYPE_DEFAULT); - if (IS_ERR(alloc)) - goto fail; - break; - - case ACL_TYPE_DEFAULT: - dfacl = acl; - alloc = acl = nfs3_proc_getacl(inode, - ACL_TYPE_ACCESS); - if (IS_ERR(alloc)) - goto fail; - break; - - default: - return -EINVAL; + case ACL_TYPE_ACCESS: + alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT); + if (IS_ERR(alloc)) + goto fail; + break; + + case ACL_TYPE_DEFAULT: + dfacl = acl; + alloc = acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(alloc)) + goto fail; + break; } - } else if (type != ACL_TYPE_ACCESS) - return -EINVAL; + } if (acl == NULL) { alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); @@ -417,24 +236,24 @@ fail: int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, umode_t mode) { - struct posix_acl *dfacl, *acl; - int error = 0; + struct posix_acl *default_acl, *acl; + int error; - dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(dfacl)) { - error = PTR_ERR(dfacl); + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) return (error == -EOPNOTSUPP) ? 0 : error; - } - if (!dfacl) - return 0; - acl = posix_acl_dup(dfacl); - error = __posix_acl_create(&acl, GFP_KERNEL, &mode); - if (error < 0) - goto out_release_dfacl; - error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? - dfacl : NULL); - posix_acl_release(acl); -out_release_dfacl: - posix_acl_release(dfacl); + + error = nfs3_proc_setacls(inode, acl, default_acl); + + if (acl) + posix_acl_release(acl); + if (default_acl) + posix_acl_release(default_acl); return error; } + +const struct xattr_handler *nfs3_xattr_handlers[] = { + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, + NULL, +}; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 01b6f6a..d2255d7 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -317,8 +317,8 @@ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call create %pd\n", dentry); @@ -340,7 +340,9 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, data->arg.create.verifier[1] = cpu_to_be32(current->pid); } - sattr->ia_mode &= ~current_umask(); + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; for (;;) { status = nfs3_do_create(dir, dentry, data); @@ -366,7 +368,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, } if (status != 0) - goto out; + goto out_release_acls; /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ @@ -385,9 +387,14 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) - goto out; + goto out_release_acls; } - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply create: %d\n", status); @@ -572,18 +579,20 @@ out: static int nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mkdir %pd\n", dentry); - sattr->ia_mode &= ~current_umask(); - data = nfs3_alloc_createdata(); if (data == NULL) goto out; + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; + data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; data->arg.mkdir.fh = NFS_FH(dir); data->arg.mkdir.name = dentry->d_name.name; @@ -592,9 +601,13 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) status = nfs3_do_create(dir, dentry, data); if (status != 0) - goto out; + goto out_release_acls; - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mkdir: %d\n", status); @@ -691,19 +704,21 @@ static int nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mknod %pd %u:%u\n", dentry, MAJOR(rdev), MINOR(rdev)); - sattr->ia_mode &= ~current_umask(); - data = nfs3_alloc_createdata(); if (data == NULL) goto out; + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; + data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; data->arg.mknod.fh = NFS_FH(dir); data->arg.mknod.name = dentry->d_name.name; @@ -731,8 +746,13 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, status = nfs3_do_create(dir, dentry, data); if (status != 0) - goto out; - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + goto out_release_acls; + + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mknod: %d\n", status); @@ -904,20 +924,28 @@ static const struct inode_operations nfs3_dir_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, - .listxattr = nfs3_listxattr, - .getxattr = nfs3_getxattr, - .setxattr = nfs3_setxattr, - .removexattr = nfs3_removexattr, + .listxattr = generic_listxattr, + .getxattr = generic_getxattr, + .setxattr = generic_setxattr, + .removexattr = generic_removexattr, +#ifdef CONFIG_NFS_V3_ACL + .get_acl = nfs3_get_acl, + .set_acl = nfs3_set_acl, +#endif }; static const struct inode_operations nfs3_file_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, - .listxattr = nfs3_listxattr, - .getxattr = nfs3_getxattr, - .setxattr = nfs3_setxattr, - .removexattr = nfs3_removexattr, + .listxattr = generic_listxattr, + .getxattr = generic_getxattr, + .setxattr = generic_setxattr, + .removexattr = generic_removexattr, +#ifdef CONFIG_NFS_V3_ACL + .get_acl = nfs3_get_acl, + .set_acl = nfs3_set_acl, +#endif }; const struct nfs_rpc_ops nfs_v3_clientops = { @@ -965,7 +993,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare, .commit_done = nfs3_commit_done, .lock = nfs3_proc_lock, - .clear_acl_cache = nfs3_forget_cached_acls, + .clear_acl_cache = forget_all_cached_acls, .close_context = nfs_close_context, .have_delegation = nfs3_have_delegation, .return_delegation = nfs3_return_delegation, diff --git a/fs/nfs/nfs3super.c b/fs/nfs/nfs3super.c index cc471c7..d6a9894 100644 --- a/fs/nfs/nfs3super.c +++ b/fs/nfs/nfs3super.c @@ -12,6 +12,9 @@ static struct nfs_subversion nfs_v3 = { .rpc_vers = &nfs_version3, .rpc_ops = &nfs_v3_clientops, .sops = &nfs_sops, +#ifdef CONFIG_NFS_V3_ACL + .xattr = nfs3_xattr_handlers, +#endif }; static int __init init_nfs_v3(void) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 4899737..2b00625 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -154,10 +154,6 @@ struct nfs_inode { struct rb_root access_cache; struct list_head access_cache_entry_lru; struct list_head access_cache_inode_lru; -#ifdef CONFIG_NFS_V3_ACL - struct posix_acl *acl_access; - struct posix_acl *acl_default; -#endif /* * This is the cookie verifier used for NFSv3 readdir @@ -564,23 +560,17 @@ extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, * linux/fs/nfs3proc.c */ #ifdef CONFIG_NFS_V3_ACL -extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); -extern int nfs3_proc_setacl(struct inode *inode, int type, - struct posix_acl *acl); -extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, - umode_t mode); -extern void nfs3_forget_cached_acls(struct inode *inode); +extern struct posix_acl *nfs3_get_acl(struct inode *inode, int type); +extern int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type); +extern int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl); +extern const struct xattr_handler *nfs3_xattr_handlers[]; #else -static inline int nfs3_proc_set_default_acl(struct inode *dir, - struct inode *inode, - umode_t mode) +static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) { return 0; } - -static inline void nfs3_forget_cached_acls(struct inode *inode) -{ -} #endif /* CONFIG_NFS_V3_ACL */ /* diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index f7e6f6c..3d14be8 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -191,6 +191,10 @@ static inline int posix_acl_create(struct inode *inode, umode_t *mode, *default_acl = *acl = NULL; return 0; } + +static inline void forget_all_cached_acls(struct inode *inode) +{ +} #endif /* CONFIG_FS_POSIX_ACL */ struct posix_acl *get_acl(struct inode *inode, int type); -- cgit v0.10.2 From feda821e76f3bbbba4bd54d30b4d4005a7848aa5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:54 -0800 Subject: fs: remove generic_acl And instead convert tmpfs to use the new generic ACL code, with two stub methods provided for in-memory filesystems. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/Kconfig b/fs/Kconfig index c229f82..7385e54 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -68,10 +68,6 @@ source "fs/quota/Kconfig" source "fs/autofs4/Kconfig" source "fs/fuse/Kconfig" -config GENERIC_ACL - bool - select FS_POSIX_ACL - menu "Caches" source "fs/fscache/Kconfig" @@ -119,7 +115,7 @@ config TMPFS_POSIX_ACL bool "Tmpfs POSIX Access Control Lists" depends on TMPFS select TMPFS_XATTR - select GENERIC_ACL + select FS_POSIX_ACL help POSIX Access Control Lists (ACLs) support additional access rights for users and groups beyond the standard owner/group/world scheme, diff --git a/fs/Makefile b/fs/Makefile index f2c1843..5bebad4 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -44,7 +44,6 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ -obj-$(CONFIG_GENERIC_ACL) += generic_acl.o obj-$(CONFIG_COREDUMP) += coredump.o obj-$(CONFIG_SYSCTL) += drop_caches.o diff --git a/fs/generic_acl.c b/fs/generic_acl.c deleted file mode 100644 index 4357f39..0000000 --- a/fs/generic_acl.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * (C) 2005 Andreas Gruenbacher - * - * This file is released under the GPL. - * - * Generic ACL support for in-memory filesystems. - */ - -#include -#include -#include -#include -#include -#include - - -static size_t -generic_acl_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - struct posix_acl *acl; - const char *xname; - size_t size; - - acl = get_cached_acl(dentry->d_inode, type); - if (!acl) - return 0; - posix_acl_release(acl); - - switch (type) { - case ACL_TYPE_ACCESS: - xname = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - xname = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return 0; - } - size = strlen(xname) + 1; - if (list && size <= list_size) - memcpy(list, xname, size); - return size; -} - -static int -generic_acl_get(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; - - acl = get_cached_acl(dentry->d_inode, type); - if (!acl) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -generic_acl_set(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (acl) { - error = posix_acl_valid(acl); - if (error) - goto failed; - switch (type) { - case ACL_TYPE_ACCESS: - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) - goto failed; - inode->i_ctime = CURRENT_TIME; - if (error == 0) { - posix_acl_release(acl); - acl = NULL; - } - break; - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) { - error = -EINVAL; - goto failed; - } - break; - } - } - set_cached_acl(inode, type, acl); - error = 0; -failed: - posix_acl_release(acl); - return error; -} - -/** - * generic_acl_init - Take care of acl inheritance at @inode create time - * - * Files created inside a directory with a default ACL inherit the - * directory's default ACL. - */ -int -generic_acl_init(struct inode *inode, struct inode *dir) -{ - struct posix_acl *acl = NULL; - int error; - - if (!S_ISLNK(inode->i_mode)) - acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); - if (acl) { - if (S_ISDIR(inode->i_mode)) - set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - } else { - inode->i_mode &= ~current_umask(); - } - error = 0; - - posix_acl_release(acl); - return error; -} - -/** - * generic_acl_chmod - change the access acl of @inode upon chmod() - * - * A chmod also changes the permissions of the owner, group/mask, and - * other ACL entries. - */ -int -generic_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error = 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = get_cached_acl(inode, ACL_TYPE_ACCESS); - if (acl) { - error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - } - return error; -} - -const struct xattr_handler generic_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = generic_acl_list, - .get = generic_acl_get, - .set = generic_acl_set, -}; - -const struct xattr_handler generic_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = generic_acl_list, - .get = generic_acl_get, - .set = generic_acl_set, -}; diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 8f245ab..f40df9b 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -786,3 +786,39 @@ const struct xattr_handler posix_acl_default_xattr_handler = { .set = posix_acl_xattr_set, }; EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); + +int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int error; + + if (type == ACL_TYPE_ACCESS) { + error = posix_acl_equiv_mode(acl, &inode->i_mode); + if (error < 0) + return 0; + if (error == 0) + acl = NULL; + } + + inode->i_ctime = CURRENT_TIME; + set_cached_acl(inode, type, acl); + return 0; +} + +int simple_acl_create(struct inode *dir, struct inode *inode) +{ + struct posix_acl *default_acl, *acl; + int error; + + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; + + set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); + return 0; +} diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h deleted file mode 100644 index b6d6575..0000000 --- a/include/linux/generic_acl.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef LINUX_GENERIC_ACL_H -#define LINUX_GENERIC_ACL_H - -#include - -struct inode; - -extern const struct xattr_handler generic_acl_access_handler; -extern const struct xattr_handler generic_acl_default_handler; - -int generic_acl_init(struct inode *, struct inode *); -int generic_acl_chmod(struct inode *); - -#endif /* LINUX_GENERIC_ACL_H */ diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 3d14be8..6b12b3d 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -99,6 +99,9 @@ extern int posix_acl_chmod(struct inode *, umode_t); extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, struct posix_acl **); +extern int simple_set_acl(struct inode *, struct posix_acl *, int); +extern int simple_acl_create(struct inode *, struct inode *); + static inline struct posix_acl **acl_by_type(struct inode *inode, int type) { switch (type) { @@ -181,6 +184,12 @@ static inline int posix_acl_chmod(struct inode *inode, umode_t mode) return 0; } +#define simple_set_acl NULL + +static inline int simple_acl_create(struct inode *dir, struct inode *inode) +{ + return 0; +} static inline void cache_no_acl(struct inode *inode) { } diff --git a/mm/shmem.c b/mm/shmem.c index 902a148..b21ca54 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -45,7 +45,7 @@ static struct vfsmount *shm_mnt; #include #include #include -#include +#include #include #include #include @@ -620,10 +620,8 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) } setattr_copy(inode, attr); -#ifdef CONFIG_TMPFS_POSIX_ACL if (attr->ia_valid & ATTR_MODE) - error = generic_acl_chmod(inode); -#endif + error = posix_acl_chmod(inode, inode->i_mode); return error; } @@ -1937,22 +1935,14 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE); if (inode) { -#ifdef CONFIG_TMPFS_POSIX_ACL - error = generic_acl_init(inode, dir); - if (error) { - iput(inode); - return error; - } -#endif + error = simple_acl_create(dir, inode); + if (error) + goto out_iput; error = security_inode_init_security(inode, dir, &dentry->d_name, shmem_initxattrs, NULL); - if (error) { - if (error != -EOPNOTSUPP) { - iput(inode); - return error; - } - } + if (error && error != -EOPNOTSUPP) + goto out_iput; error = 0; dir->i_size += BOGO_DIRENT_SIZE; @@ -1961,6 +1951,9 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) dget(dentry); /* Extra count - pin the dentry in core */ } return error; +out_iput: + iput(inode); + return error; } static int @@ -1974,24 +1967,17 @@ shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) error = security_inode_init_security(inode, dir, NULL, shmem_initxattrs, NULL); - if (error) { - if (error != -EOPNOTSUPP) { - iput(inode); - return error; - } - } -#ifdef CONFIG_TMPFS_POSIX_ACL - error = generic_acl_init(inode, dir); - if (error) { - iput(inode); - return error; - } -#else - error = 0; -#endif + if (error && error != -EOPNOTSUPP) + goto out_iput; + error = simple_acl_create(dir, inode); + if (error) + goto out_iput; d_tmpfile(dentry, inode); } return error; +out_iput: + iput(inode); + return error; } static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) @@ -2223,8 +2209,8 @@ static int shmem_initxattrs(struct inode *inode, static const struct xattr_handler *shmem_xattr_handlers[] = { #ifdef CONFIG_TMPFS_POSIX_ACL - &generic_acl_access_handler, - &generic_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; @@ -2740,6 +2726,7 @@ static const struct inode_operations shmem_inode_operations = { .getxattr = shmem_getxattr, .listxattr = shmem_listxattr, .removexattr = shmem_removexattr, + .set_acl = simple_set_acl, #endif }; @@ -2764,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = { #endif #ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_setattr, + .set_acl = simple_set_acl, #endif }; @@ -2776,6 +2764,7 @@ static const struct inode_operations shmem_special_inode_operations = { #endif #ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_setattr, + .set_acl = simple_set_acl, #endif }; -- cgit v0.10.2 From 4ac7249ea5a0ceef9f8269f63f33cc873c3fac61 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:55 -0800 Subject: nfsd: use get_acl and ->set_acl Remove the boilerplate code to marshall and unmarhall ACL objects into xattrs and operate on the posix_acl objects directly. Also move all the ACL handling code into nfs?acl.c where it belongs. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index 8b186a4..8b68218 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h @@ -35,7 +35,9 @@ #ifndef LINUX_NFS4_ACL_H #define LINUX_NFS4_ACL_H -#include +struct nfs4_acl; +struct svc_fh; +struct svc_rqst; /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to * fit in a page: */ @@ -45,13 +47,9 @@ struct nfs4_acl *nfs4_acl_new(int); int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_write_who(int who, char *p); -#define NFS4_ACL_TYPE_DEFAULT 0x01 -#define NFS4_ACL_DIR 0x02 -#define NFS4_ACL_OWNER 0x04 - -struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *, - struct posix_acl *, unsigned int flags); -int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **, - struct posix_acl **, unsigned int flags); +int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct nfs4_acl **acl); +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct nfs4_acl *acl); #endif /* LINUX_NFS4_ACL_H */ diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 95d76dc..11c1fba 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { - svc_fh *fh; struct posix_acl *acl; + struct inode *inode; + svc_fh *fh; __be32 nfserr = 0; dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); @@ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); + inode = fh->fh_dentry->d_inode; + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; @@ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, goto fail; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { - acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } if (acl == NULL) { /* Solaris returns the inode's minimum ACL. */ - - struct inode *inode = fh->fh_dentry->d_inode; acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } resp->acl_access = acl; @@ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { /* Check how Solaris handles requests for the Default ACL of a non-directory! */ - - acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } resp->acl_default = acl; } @@ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd_attrstat *resp) { + struct inode *inode; svc_fh *fh; __be32 nfserr = 0; + int error; dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (nfserr) + goto out; - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_ACCESS, argp->acl_access) ); - } - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_DEFAULT, argp->acl_default) ); - } - if (!nfserr) { - nfserr = fh_getattr(fh, &resp->stat); + inode = fh->fh_dentry->d_inode; + if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { + error = -EOPNOTSUPP; + goto out_errno; } + error = fh_want_write(fh); + if (error) + goto out_errno; + + error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); + if (error) + goto out_drop_write; + error = inode->i_op->set_acl(inode, argp->acl_default, + ACL_TYPE_DEFAULT); + if (error) + goto out_drop_write; + + fh_drop_write(fh); + + nfserr = fh_getattr(fh, &resp->stat); + +out: /* argp->acl_{access,default} may have been allocated in nfssvc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); return nfserr; +out_drop_write: + fh_drop_write(fh); +out_errno: + nfserr = nfserrno(error); + goto out; } /* diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 9cbc1a8..adc5f1b 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -29,8 +29,9 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { - svc_fh *fh; struct posix_acl *acl; + struct inode *inode; + svc_fh *fh; __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); @@ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); + inode = fh->fh_dentry->d_inode; + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { - acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } if (acl == NULL) { /* Solaris returns the inode's minimum ACL. */ - - struct inode *inode = fh->fh_dentry->d_inode; acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } resp->acl_access = acl; @@ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { /* Check how Solaris handles requests for the Default ACL of a non-directory! */ - - acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } resp->acl_default = acl; } @@ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd3_attrstat *resp) { + struct inode *inode; svc_fh *fh; __be32 nfserr = 0; + int error; fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (nfserr) + goto out; - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_ACCESS, argp->acl_access) ); - } - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_DEFAULT, argp->acl_default) ); + inode = fh->fh_dentry->d_inode; + if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { + error = -EOPNOTSUPP; + goto out_errno; } + error = fh_want_write(fh); + if (error) + goto out_errno; + + error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); + if (error) + goto out_drop_write; + error = inode->i_op->set_acl(inode, argp->acl_default, + ACL_TYPE_DEFAULT); + +out_drop_write: + fh_drop_write(fh); +out_errno: + nfserr = nfserrno(error); +out: /* argp->acl_{access,default} may have been allocated in nfs3svc_decode_setaclargs. */ posix_acl_release(argp->acl_access); diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 8a50b3c..649ad7c 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -37,8 +37,13 @@ #include #include #include +#include "nfsfh.h" #include "acl.h" +#include "vfs.h" +#define NFS4_ACL_TYPE_DEFAULT 0x01 +#define NFS4_ACL_DIR 0x02 +#define NFS4_ACL_OWNER 0x04 /* mode bit translations: */ #define NFS4_READ_MODE (NFS4_ACE_READ_DATA) @@ -130,36 +135,50 @@ static short ace2type(struct nfs4_ace *); static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); -struct nfs4_acl * -nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, - unsigned int flags) +int +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct nfs4_acl **acl) { - struct nfs4_acl *acl; + struct inode *inode = dentry->d_inode; + int error = 0; + struct posix_acl *pacl = NULL, *dpacl = NULL; + unsigned int flags = 0; int size = 0; - if (pacl) { - if (posix_acl_valid(pacl) < 0) - return ERR_PTR(-EINVAL); - size += 2*pacl->a_count; + pacl = get_acl(inode, ACL_TYPE_ACCESS); + if (!pacl) { + pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + if (IS_ERR(pacl)) + return PTR_ERR(pacl); + /* allocate for worst case: one (deny, allow) pair each: */ + size += 2 * pacl->a_count; } - if (dpacl) { - if (posix_acl_valid(dpacl) < 0) - return ERR_PTR(-EINVAL); - size += 2*dpacl->a_count; + + if (S_ISDIR(inode->i_mode)) { + flags = NFS4_ACL_DIR; + dpacl = get_acl(inode, ACL_TYPE_DEFAULT); + if (dpacl) + size += 2 * dpacl->a_count; + } else { + dpacl = NULL; } - /* Allocate for worst case: one (deny, allow) pair each: */ - acl = nfs4_acl_new(size); - if (acl == NULL) - return ERR_PTR(-ENOMEM); + *acl = nfs4_acl_new(size); + if (*acl == NULL) { + error = -ENOMEM; + goto out; + } if (pacl) - _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT); + _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); if (dpacl) - _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT); + _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); - return acl; + out: + posix_acl_release(pacl); + posix_acl_release(dpacl); + return error; } struct posix_acl_summary { @@ -719,8 +738,9 @@ static void process_one_v4_ace(struct posix_acl_state *state, } } -int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, - struct posix_acl **dpacl, unsigned int flags) +static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, + struct posix_acl **pacl, struct posix_acl **dpacl, + unsigned int flags) { struct posix_acl_state effective_acl_state, default_acl_state; struct nfs4_ace *ace; @@ -780,6 +800,57 @@ out_estate: return ret; } +__be32 +nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct nfs4_acl *acl) +{ + __be32 error; + int host_error; + struct dentry *dentry; + struct inode *inode; + struct posix_acl *pacl = NULL, *dpacl = NULL; + unsigned int flags = 0; + + /* Get inode */ + error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); + if (error) + return error; + + dentry = fhp->fh_dentry; + inode = dentry->d_inode; + + if (!inode->i_op->set_acl || !IS_POSIXACL(inode)) + return nfserr_attrnotsupp; + + if (S_ISDIR(inode->i_mode)) + flags = NFS4_ACL_DIR; + + host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + if (host_error == -EINVAL) + return nfserr_attrnotsupp; + if (host_error < 0) + goto out_nfserr; + + host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS); + if (host_error < 0) + goto out_release; + + if (S_ISDIR(inode->i_mode)) { + host_error = inode->i_op->set_acl(inode, dpacl, + ACL_TYPE_DEFAULT); + } + +out_release: + posix_acl_release(pacl); + posix_acl_release(dpacl); +out_nfserr: + if (host_error == -EOPNOTSUPP) + return nfserr_attrnotsupp; + else + return nfserrno(host_error); +} + + static short ace2type(struct nfs4_ace *ace) { @@ -798,9 +869,6 @@ ace2type(struct nfs4_ace *ace) return -1; } -EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); -EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); - struct nfs4_acl * nfs4_acl_new(int n) { @@ -862,7 +930,3 @@ nfs4_acl_write_who(int who, char *p) BUG(); return -1; } - -EXPORT_SYMBOL(nfs4_acl_new); -EXPORT_SYMBOL(nfs4_acl_get_whotype); -EXPORT_SYMBOL(nfs4_acl_write_who); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 419572f..825b8a9 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -41,6 +41,7 @@ #include "vfs.h" #include "current_stateid.h" #include "netns.h" +#include "acl.h" #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #include diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7eea63c..1426eb6 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -468,158 +468,7 @@ out: return err; } -#if defined(CONFIG_NFSD_V2_ACL) || \ - defined(CONFIG_NFSD_V3_ACL) || \ - defined(CONFIG_NFSD_V4) -static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) -{ - ssize_t buflen; - ssize_t ret; - - buflen = vfs_getxattr(dentry, key, NULL, 0); - if (buflen <= 0) - return buflen; - - *buf = kmalloc(buflen, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - - ret = vfs_getxattr(dentry, key, *buf, buflen); - if (ret < 0) - kfree(*buf); - return ret; -} -#endif - #if defined(CONFIG_NFSD_V4) -static int -set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) -{ - int len; - size_t buflen; - char *buf = NULL; - int error = 0; - - buflen = posix_acl_xattr_size(pacl->a_count); - buf = kmalloc(buflen, GFP_KERNEL); - error = -ENOMEM; - if (buf == NULL) - goto out; - - len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen); - if (len < 0) { - error = len; - goto out; - } - - error = vfs_setxattr(dentry, key, buf, len, 0); -out: - kfree(buf); - return error; -} - -__be32 -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl) -{ - __be32 error; - int host_error; - struct dentry *dentry; - struct inode *inode; - struct posix_acl *pacl = NULL, *dpacl = NULL; - unsigned int flags = 0; - - /* Get inode */ - error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); - if (error) - return error; - - dentry = fhp->fh_dentry; - inode = dentry->d_inode; - if (S_ISDIR(inode->i_mode)) - flags = NFS4_ACL_DIR; - - host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); - if (host_error == -EINVAL) { - return nfserr_attrnotsupp; - } else if (host_error < 0) - goto out_nfserr; - - host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (host_error < 0) - goto out_release; - - if (S_ISDIR(inode->i_mode)) - host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); - -out_release: - posix_acl_release(pacl); - posix_acl_release(dpacl); -out_nfserr: - if (host_error == -EOPNOTSUPP) - return nfserr_attrnotsupp; - else - return nfserrno(host_error); -} - -static struct posix_acl * -_get_posix_acl(struct dentry *dentry, char *key) -{ - void *buf = NULL; - struct posix_acl *pacl = NULL; - int buflen; - - buflen = nfsd_getxattr(dentry, key, &buf); - if (!buflen) - buflen = -ENODATA; - if (buflen <= 0) - return ERR_PTR(buflen); - - pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen); - kfree(buf); - return pacl; -} - -int -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - struct posix_acl *pacl = NULL, *dpacl = NULL; - unsigned int flags = 0; - - pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); - if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) - pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); - if (IS_ERR(pacl)) { - error = PTR_ERR(pacl); - pacl = NULL; - goto out; - } - - if (S_ISDIR(inode->i_mode)) { - dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); - if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) - dpacl = NULL; - else if (IS_ERR(dpacl)) { - error = PTR_ERR(dpacl); - dpacl = NULL; - goto out; - } - flags = NFS4_ACL_DIR; - } - - *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags); - if (IS_ERR(*acl)) { - error = PTR_ERR(*acl); - *acl = NULL; - } - out: - posix_acl_release(pacl); - posix_acl_release(dpacl); - return error; -} - /* * NFS junction information is stored in an extended attribute. */ @@ -2284,93 +2133,3 @@ out_nomem: nfsd_racache_shutdown(); return -ENOMEM; } - -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -struct posix_acl * -nfsd_get_posix_acl(struct svc_fh *fhp, int type) -{ - struct inode *inode = fhp->fh_dentry->d_inode; - char *name; - void *value = NULL; - ssize_t size; - struct posix_acl *acl; - - if (!IS_POSIXACL(inode)) - return ERR_PTR(-EOPNOTSUPP); - - switch (type) { - case ACL_TYPE_ACCESS: - name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return ERR_PTR(-EOPNOTSUPP); - } - - size = nfsd_getxattr(fhp->fh_dentry, name, &value); - if (size < 0) - return ERR_PTR(size); - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - kfree(value); - return acl; -} - -int -nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) -{ - struct inode *inode = fhp->fh_dentry->d_inode; - char *name; - void *value = NULL; - size_t size; - int error; - - if (!IS_POSIXACL(inode) || - !inode->i_op->setxattr || !inode->i_op->removexattr) - return -EOPNOTSUPP; - switch(type) { - case ACL_TYPE_ACCESS: - name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return -EOPNOTSUPP; - } - - if (acl && acl->a_count) { - size = posix_acl_xattr_size(acl->a_count); - value = kmalloc(size, GFP_KERNEL); - if (!value) - return -ENOMEM; - error = posix_acl_to_xattr(&init_user_ns, acl, value, size); - if (error < 0) - goto getout; - size = error; - } else - size = 0; - - error = fh_want_write(fhp); - if (error) - goto getout; - if (size) - error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); - else { - if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) - error = 0; - else { - error = vfs_removexattr(fhp->fh_dentry, name); - if (error == -ENODATA) - error = 0; - } - } - fh_drop_write(fhp); - -getout: - kfree(value); - return error; -} -#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index a4be2e3..1bc1d44 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -52,9 +52,6 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *, int, time_t); int nfsd_mountpoint(struct dentry *, struct svc_export *); #ifdef CONFIG_NFSD_V4 -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, - struct nfs4_acl *); -int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, struct xdr_netobj *); #endif /* CONFIG_NFSD_V4 */ @@ -101,11 +98,6 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, struct dentry *, int); -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); -int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); -#endif - static inline int fh_want_write(struct svc_fh *fh) { int ret = mnt_want_write(fh->fh_export->ex_path.mnt); -- cgit v0.10.2 From 2796e4cec525a2b1cace3b29b2f02735dafea007 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 Dec 2013 05:16:56 -0800 Subject: hfsplus: remove can_set_xattr When using the per-superblock xattr handlers permission checking is done by the generic code. hfsplus just needs to check for the magic osx attribute not to leak into protected namespaces. Also given that the code was obviously copied from JFS the proper attribution was missing. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index bf88baa..0b4a5c9 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -52,82 +52,6 @@ static inline int is_known_namespace(const char *name) return true; } -static int can_set_system_xattr(struct inode *inode, const char *name, - const void *value, size_t size) -{ -#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL - struct posix_acl *acl; - int err; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - /* - * POSIX_ACL_XATTR_ACCESS is tied to i_mode - */ - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - err = posix_acl_equiv_mode(acl, &inode->i_mode); - posix_acl_release(acl); - if (err < 0) - return err; - mark_inode_dirty(inode); - } - /* - * We're changing the ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_ACCESS); - - return 0; - } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - posix_acl_release(acl); - - /* - * We're changing the default ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_DEFAULT); - - return 0; - } -#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */ - return -EOPNOTSUPP; -} - -static int can_set_xattr(struct inode *inode, const char *name, - const void *value, size_t value_len) -{ - if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) - return can_set_system_xattr(inode, name, value, value_len); - - if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { - /* - * This makes sure that we aren't trying to set an - * attribute in a different namespace by prefixing it - * with "osx." - */ - if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) - return -EOPNOTSUPP; - - return 0; - } - - /* - * Don't allow setting an attribute in an unknown namespace. - */ - if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && - strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && - strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) - return -EOPNOTSUPP; - - return 0; -} - static void hfsplus_init_header_node(struct inode *attr_file, u32 clump_size, char *buf, u16 node_size) @@ -350,10 +274,6 @@ int __hfsplus_setxattr(struct inode *inode, const char *name, HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; - err = can_set_xattr(inode, name, value, size); - if (err) - return err; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN) == 0) name += XATTR_MAC_OSX_PREFIX_LEN; @@ -841,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name) if (!HFSPLUS_SB(inode->i_sb)->attr_tree) return -EOPNOTSUPP; - err = can_set_xattr(inode, name, NULL, 0); - if (err) - return err; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN) == 0) name += XATTR_MAC_OSX_PREFIX_LEN; @@ -941,6 +857,9 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, if (len > HFSPLUS_ATTR_MAX_STRLEN) return -EOPNOTSUPP; + if (is_known_namespace(name)) + return -EOPNOTSUPP; + strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); -- cgit v0.10.2 From 9fe55eea7e4b444bafc42fa0000cc2d1d2847275 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 24 Jan 2014 14:42:22 +0000 Subject: Fix race when checking i_size on direct i/o read So far I've had one ACK for this, and no other comments. So I think it is probably time to send this via some suitable tree. I'm guessing that the vfs tree would be the most appropriate route, but not sure that there is one at the moment (don't see anything recent at kernel.org) so in that case I think -mm is the "back up plan". Al, please let me know if you will take this? Steve. --------------------- Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio reads with append dio writes" thread on linux-fsdevel, this patch is my current version of the fix proposed as option (b) in that thread. Removing the i_size test from the direct i/o read path at vfs level means that filesystems now have to deal with requests which are beyond i_size themselves. These I've divided into three sets: a) Those with "no op" ->direct_IO (9p, cifs, ceph) These are obviously not going to be an issue b) Those with "home brew" ->direct_IO (nfs, fuse) I've been told that NFS should not have any problem with the larger i_size, however I've added an extra test to FUSE to duplicate the original behaviour just to be on the safe side. c) Those using __blockdev_direct_IO() These call through to ->get_block() which should deal with the EOF condition correctly. I've verified that with GFS2 and I believe that Zheng has verified it for ext4. I've also run the test on XFS and it passes both before and after this change. The part of the patch in filemap.c looks a lot larger than it really is - there are only two lines of real change. The rest is just indentation of the contained code. There remains a test of i_size though, which was added for btrfs. It doesn't cause the other filesystems a problem as the test is performed after ->direct_IO has been called. It is possible that there is a race that does matter to btrfs, however this patch doesn't change that, so its still an overall improvement. Signed-off-by: Steven Whitehouse Reported-by: Zheng Liu Cc: Jan Kara Cc: Dave Chinner Acked-by: Miklos Szeredi Cc: Chris Mason Cc: Josef Bacik Cc: Christoph Hellwig Cc: Alexander Viro Signed-off-by: Al Viro diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 7e70506..89fdfd1 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2710,6 +2710,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, inode = file->f_mapping->host; i_size = i_size_read(inode); + if ((rw == READ) && (offset > i_size)) + return 0; + /* optimization for short read */ if (async_dio && rw != WRITE && offset + count > i_size) { if (offset >= i_size) diff --git a/mm/filemap.c b/mm/filemap.c index b7749a9..0184286 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1428,30 +1428,28 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (!count) goto out; /* skip atime */ size = i_size_read(inode); - if (pos < size) { - retval = filemap_write_and_wait_range(mapping, pos, + retval = filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1); - if (!retval) { - retval = mapping->a_ops->direct_IO(READ, iocb, - iov, pos, nr_segs); - } - if (retval > 0) { - *ppos = pos + retval; - count -= retval; - } + if (!retval) { + retval = mapping->a_ops->direct_IO(READ, iocb, + iov, pos, nr_segs); + } + if (retval > 0) { + *ppos = pos + retval; + count -= retval; + } - /* - * Btrfs can have a short DIO read if we encounter - * compressed extents, so if there was an error, or if - * we've already read everything we wanted to, or if - * there was a short read because we hit EOF, go ahead - * and return. Otherwise fallthrough to buffered io for - * the rest of the read. - */ - if (retval < 0 || !count || *ppos >= size) { - file_accessed(filp); - goto out; - } + /* + * Btrfs can have a short DIO read if we encounter + * compressed extents, so if there was an error, or if + * we've already read everything we wanted to, or if + * there was a short read because we hit EOF, go ahead + * and return. Otherwise fallthrough to buffered io for + * the rest of the read. + */ + if (retval < 0 || !count || *ppos >= size) { + file_accessed(filp); + goto out; } } -- cgit v0.10.2 From 260a459d2e39761fbd39803497205ce1690bc7b1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Jan 2014 15:26:15 -0800 Subject: vfs: Is mounted should be testing mnt_ns for NULL or error. A bug was introduced with the is_mounted helper function in commit f7a99c5b7c8bd3d3f533c8b38274e33f3da9096e Author: Al Viro Date: Sat Jun 9 00:59:08 2012 -0400 get rid of ->mnt_longterm it's enough to set ->mnt_ns of internal vfsmounts to something distinct from all struct mnt_namespace out there; then we can just use the check for ->mnt_ns != NULL in the fast path of mntput_no_expire() Signed-off-by: Al Viro The intent was to test if the real_mount(vfsmount)->mnt_ns was NULL_OR_ERR but the code is actually testing real_mount(vfsmount) and always returning true. The result is d_absolute_path returning paths it should be hiding. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro diff --git a/fs/mount.h b/fs/mount.h index d64c594..a17458c 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -74,7 +74,7 @@ static inline int mnt_has_parent(struct mount *mnt) static inline int is_mounted(struct vfsmount *mnt) { /* neither detached nor internal? */ - return !IS_ERR_OR_NULL(real_mount(mnt)); + return !IS_ERR_OR_NULL(real_mount(mnt)->mnt_ns); } extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); -- cgit v0.10.2 From a8323da0366d3398eda62741d2ac1130c8a172ed Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Jan 2014 15:43:25 -0800 Subject: vfs: Remove second variable named error in __dentry_path In commit 232d2d60aa5469bb097f55728f65146bd49c1d25 Author: Waiman Long Date: Mon Sep 9 12:18:13 2013 -0400 dcache: Translating dentry into pathname without taking rename_lock The __dentry_path locking was changed and the variable error was intended to be moved outside of the loop. Unfortunately the inner declaration of error was not removed. Resulting in a version of __dentry_path that will never return an error. Remove the problematic inner declaration of error and allow __dentry_path to return errors once again. Cc: stable@vger.kernel.org Cc: Waiman Long Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro diff --git a/fs/dcache.c b/fs/dcache.c index cb4a106..fdbe230 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3135,7 +3135,6 @@ restart: read_seqbegin_or_lock(&rename_lock, &seq); while (!IS_ROOT(dentry)) { struct dentry *parent = dentry->d_parent; - int error; prefetch(parent); error = prepend_name(&end, &len, &dentry->d_name); -- cgit v0.10.2 From f6500801522c61782d4990fa1ad96154cb397cd4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 26 Jan 2014 12:37:55 -0500 Subject: __dentry_path() fixes * we need to save the starting point for restarts * reject pathologically short buffers outright Spotted-by: Denys Vlasenko Spotted-by: Oleg Nesterov Signed-off-by: Al Viro diff --git a/fs/dcache.c b/fs/dcache.c index fdbe230..265e0ce 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3116,19 +3116,22 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) /* * Write full pathname from the root of the filesystem into the buffer. */ -static char *__dentry_path(struct dentry *dentry, char *buf, int buflen) +static char *__dentry_path(struct dentry *d, char *buf, int buflen) { + struct dentry *dentry; char *end, *retval; int len, seq = 0; int error = 0; + if (buflen < 2) + goto Elong; + rcu_read_lock(); restart: + dentry = d; end = buf + buflen; len = buflen; prepend(&end, &len, "\0", 1); - if (buflen < 1) - goto Elong; /* Get '/' right */ retval = end-1; *retval = '/'; -- cgit v0.10.2