Commit 12538ad0 authored by Theodore Y. Ts'o's avatar Theodore Y. Ts'o Committed by Linus Torvalds

Port of (bugfixed) 0.8.50 acl-ext2 to 2.5

This patch adds ACL support to the ext2 filesystem.
parent 651d4694
......@@ -970,6 +970,18 @@ config EXT2_FS_XATTR
If unsure, say N.
config EXT2_FS_POSIX_ACL
bool "Ext2 POSIX Access Control Lists"
depends on EXT2_FS_XATTR
---help---
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
To learn more about Access Control Lists, visit the Posix ACLs for
Linux website <http://acl.bestbits.at/>.
If you don't know what Access Control Lists are, say N
config SYSV_FS
tristate "System V/Xenix/V7/Coherent file system support"
---help---
......
......@@ -13,4 +13,8 @@ ifeq ($(CONFIG_EXT2_FS_XATTR),y)
ext2-objs += xattr.o xattr_user.o
endif
ifeq ($(CONFIG_EXT2_FS_POSIX_ACL),y)
ext2-objs += acl.o
endif
include $(TOPDIR)/Rules.make
This diff is collapsed.
/*
File: fs/ext2/acl.h
(C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#include <linux/xattr_acl.h>
#define EXT2_ACL_VERSION 0x0001
#define EXT2_ACL_MAX_ENTRIES 32
typedef struct {
__u16 e_tag;
__u16 e_perm;
__u32 e_id;
} ext2_acl_entry;
typedef struct {
__u16 e_tag;
__u16 e_perm;
} ext2_acl_entry_short;
typedef struct {
__u32 a_version;
} ext2_acl_header;
static inline size_t ext2_acl_size(int count)
{
if (count <= 4) {
return sizeof(ext2_acl_header) +
count * sizeof(ext2_acl_entry_short);
} else {
return sizeof(ext2_acl_header) +
4 * sizeof(ext2_acl_entry_short) +
(count - 4) * sizeof(ext2_acl_entry);
}
}
static inline int ext2_acl_count(size_t size)
{
ssize_t s;
size -= sizeof(ext2_acl_header);
s = size - 4 * sizeof(ext2_acl_entry_short);
if (s < 0) {
if (size % sizeof(ext2_acl_entry_short))
return -1;
return size / sizeof(ext2_acl_entry_short);
} else {
if (s % sizeof(ext2_acl_entry))
return -1;
return s / sizeof(ext2_acl_entry) + 4;
}
}
#ifdef CONFIG_EXT2_FS_POSIX_ACL
/* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl
if the ACL has not been cached */
#define EXT2_ACL_NOT_CACHED ((void *)-1)
/* acl.c */
extern int ext2_permission (struct inode *, int);
extern int ext2_permission_locked (struct inode *, int);
extern int ext2_acl_chmod (struct inode *);
extern int ext2_init_acl (struct inode *, struct inode *);
extern int init_ext2_acl(void);
extern void exit_ext2_acl(void);
#else
#include <linux/sched.h>
#define ext2_permission NULL
#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)
{
inode->i_mode &= ~current->fs->umask;
return 0;
}
#endif
......@@ -20,6 +20,10 @@ struct ext2_inode_info {
__u32 i_prealloc_block;
__u32 i_prealloc_count;
__u32 i_dir_start_lookup;
#ifdef CONFIG_EXT2_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
rwlock_t i_meta_lock;
struct inode vfs_inode;
};
......@@ -85,6 +89,7 @@ extern void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
extern void ext2_discard_prealloc (struct inode *);
extern void ext2_truncate (struct inode *);
extern int ext2_setattr (struct dentry *, struct iattr *);
/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
......
......@@ -21,6 +21,7 @@
#include <linux/time.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/*
* Called when an inode is released. Note that this is different
......@@ -60,4 +61,6 @@ struct inode_operations ext2_file_inode_operations = {
.getxattr = ext2_getxattr,
.listxattr = ext2_listxattr,
.removexattr = ext2_removexattr,
.setattr = ext2_setattr,
.permission = ext2_permission,
};
......@@ -19,6 +19,7 @@
#include <linux/buffer_head.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/*
* ialloc.c contains the inodes allocation and deallocation routines
......@@ -302,7 +303,6 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
struct ext2_super_block * es;
struct ext2_inode_info *ei;
int err;
struct inode *ret;
sb = dir->i_sb;
inode = new_inode(sb);
......@@ -323,7 +323,6 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
goto fail;
err = -EIO;
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh)
goto fail2;
......@@ -339,6 +338,7 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
ll_rw_block(WRITE, 1, &bitmap_bh);
wait_on_buffer(bitmap_bh);
}
brelse(bitmap_bh);
ino = group * EXT2_INODES_PER_GROUP(sb) + i + 1;
if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
......@@ -395,21 +395,27 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
inode->i_flags |= S_DIRSYNC;
inode->i_generation = EXT2_SB(sb)->s_next_generation++;
insert_inode_hash(inode);
mark_inode_dirty(inode);
unlock_super(sb);
ret = inode;
if(DQUOT_ALLOC_INODE(inode)) {
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
ret = ERR_PTR(-EDQUOT);
} else {
ext2_debug("allocating inode %lu\n", inode->i_ino);
ext2_preread_inode(inode);
goto fail3;
}
goto out;
err = ext2_init_acl(inode, dir);
if (err) {
DQUOT_FREE_INODE(inode);
goto fail3;
}
mark_inode_dirty(inode);
ext2_debug("allocating inode %lu\n", inode->i_ino);
ext2_preread_inode(inode);
return inode;
fail3:
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return ERR_PTR(err);
fail2:
desc = ext2_get_group_desc (sb, group, &bh2);
......@@ -423,10 +429,10 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
unlock_super(sb);
make_bad_inode(inode);
iput(inode);
ret = ERR_PTR(err);
goto out;
return ERR_PTR(err);
bad_count:
brelse(bitmap_bh);
ext2_error (sb, "ext2_new_inode",
"Free inodes count corrupted in group %d",
group);
......@@ -439,9 +445,6 @@ struct inode * ext2_new_inode(struct inode * dir, int mode)
desc->bg_free_inodes_count = 0;
mark_buffer_dirty(bh2);
goto repeat;
out:
brelse(bitmap_bh);
return ret;
}
unsigned long ext2_count_free_inodes (struct super_block * sb)
......
......@@ -22,7 +22,6 @@
* Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000
*/
#include "ext2.h"
#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/highuid.h>
......@@ -31,6 +30,8 @@
#include <linux/module.h>
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include "ext2.h"
#include "acl.h"
MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
......@@ -982,6 +983,10 @@ void ext2_read_inode (struct inode * inode)
struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
int n;
#ifdef CONFIG_EXT2_FS_POSIX_ACL
ei->i_acl = EXT2_ACL_NOT_CACHED;
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
#endif
if (IS_ERR(raw_inode))
goto bad_inode;
......@@ -1177,3 +1182,18 @@ int ext2_sync_inode (struct inode *inode)
{
return ext2_update_inode (inode, 1);
}
int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
int error;
error = inode_change_ok(inode, iattr);
if (error)
return error;
inode_setattr(inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
error = ext2_acl_chmod(inode);
return error;
}
......@@ -32,6 +32,7 @@
#include <linux/pagemap.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/*
* Couple of helper functions - make the code slightly cleaner.
......@@ -138,7 +139,10 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int
struct inode * inode = ext2_new_inode (dir, mode);
int err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, mode, rdev);
init_special_inode(inode, inode->i_mode, rdev);
#ifdef CONFIG_EXT2_FS_EXT_ATTR
inode->i_op = &ext2_special_inode_operations;
#endif
mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode);
}
......@@ -373,6 +377,8 @@ struct inode_operations ext2_dir_inode_operations = {
.getxattr = ext2_getxattr,
.listxattr = ext2_listxattr,
.removexattr = ext2_removexattr,
.setattr = ext2_setattr,
.permission = ext2_permission,
};
struct inode_operations ext2_special_inode_operations = {
......@@ -380,4 +386,6 @@ struct inode_operations ext2_special_inode_operations = {
.getxattr = ext2_getxattr,
.listxattr = ext2_listxattr,
.removexattr = ext2_removexattr,
.setattr = ext2_setattr,
.permission = ext2_permission,
};
......@@ -28,7 +28,7 @@
#include <asm/uaccess.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es);
......@@ -155,6 +155,10 @@ static struct inode *ext2_alloc_inode(struct super_block *sb)
ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, SLAB_KERNEL);
if (!ei)
return NULL;
#ifdef CONFIG_EXT2_FS_POSIX_ACL
ei->i_acl = EXT2_ACL_NOT_CACHED;
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
#endif
return &ei->vfs_inode;
}
......@@ -191,6 +195,26 @@ static void destroy_inodecache(void)
printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n");
}
#ifdef CONFIG_EXT2_FS_POSIX_ACL
static void ext2_clear_inode(struct inode *inode)
{
struct ext2_inode_info *ei = EXT2_I(inode);
if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) {
posix_acl_release(ei->i_acl);
ei->i_acl = EXT2_ACL_NOT_CACHED;
}
if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) {
posix_acl_release(ei->i_default_acl);
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
}
}
#else
# define ext2_clear_inode NULL
#endif
static struct super_operations ext2_sops = {
.alloc_inode = ext2_alloc_inode,
.destroy_inode = ext2_destroy_inode,
......@@ -202,6 +226,7 @@ static struct super_operations ext2_sops = {
.write_super = ext2_write_super,
.statfs = ext2_statfs,
.remount_fs = ext2_remount,
.clear_inode = ext2_clear_inode,
};
/* Yes, most of these are left as NULL!!
......@@ -286,6 +311,13 @@ static int parse_options (char * options,
else if (!strcmp (this_char, "nouser_xattr"))
clear_opt (sbi->s_mount_opt, XATTR_USER);
else
#endif
#ifdef CONFIG_EXT2_FS_POSIX_ACL
if (!strcmp(this_char, "acl"))
set_opt(sbi->s_mount_opt, POSIX_ACL);
else if (!strcmp(this_char, "noacl"))
clear_opt(sbi->s_mount_opt, POSIX_ACL);
else
#endif
if (!strcmp (this_char, "bsddf"))
clear_opt (sbi->s_mount_opt, MINIX_DF);
......@@ -571,6 +603,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, NO_UID32);
if (def_mount_opts & EXT2_DEFM_XATTR_USER)
set_opt(sbi->s_mount_opt, XATTR_USER);
if (def_mount_opts & EXT2_DEFM_ACL)
set_opt(sbi->s_mount_opt, POSIX_ACL);
if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
......@@ -583,6 +617,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
if (!parse_options ((char *) data, sbi))
goto failed_mount;
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
MS_POSIXACL : 0);
if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
(EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
......@@ -828,6 +866,9 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
if (!parse_options (data, sbi))
return -EINVAL;
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
es = sbi->s_es;
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
......
......@@ -60,6 +60,7 @@
#include <asm/semaphore.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/* These symbols may be needed by a module. */
EXPORT_SYMBOL(ext2_xattr_register);
......@@ -1100,19 +1101,35 @@ init_ext2_xattr(void)
err = ext2_xattr_register(EXT2_XATTR_INDEX_USER, &ext2_xattr_user_handler);
if (err)
return err;
#ifdef CONFIG_EXT2_FS_POSIX_ACL
err = init_ext2_acl();
if (err)
goto out;
#endif
ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,
sizeof(struct mb_cache_entry) +
sizeof(struct mb_cache_entry_index), 1, 6);
if (!ext2_xattr_cache) {
ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, &ext2_xattr_user_handler);
return -ENOMEM;
err = -ENOMEM;
goto out1;
}
return 0;
out1:
#ifdef CONFIG_EXT2_FS_POSIX_ACL
exit_ext2_acl();
out:
#endif
ext2_xattr_unregister(EXT2_XATTR_INDEX_USER,
&ext2_xattr_user_handler);
return err;
}
void
exit_ext2_xattr(void)
{
mb_cache_destroy(ext2_xattr_cache);
#ifdef CONFIG_EXT2_FS_POSIX_ACL
exit_ext2_acl();
#endif
ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, &ext2_xattr_user_handler);
}
......@@ -308,6 +308,7 @@ struct ext2_inode {
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
#define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment