Commit 651d4694 authored by Theodore Y. Ts'o's avatar Theodore Y. Ts'o Committed by Linus Torvalds

Port of (bugfixed) 0.8.50 acl-ext3 to 2.5.

This patch adds ACL support to the ext3 filesystem.
parent dcdc0bd8
......@@ -300,6 +300,20 @@ config EXT3_FS_XATTR
If unsure, say N.
You need this for POSIX ACL support on ext3.
config EXT3_FS_POSIX_ACL
bool "Ext3 POSIX Access Control Lists"
depends on EXT3_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_JBD could be its own option (even modular), but until there are
# other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS
# dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
......
......@@ -13,4 +13,8 @@ ifeq ($(CONFIG_EXT3_FS_XATTR),y)
ext3-objs += xattr.o xattr_user.o
endif
ifeq ($(CONFIG_EXT3_FS_POSIX_ACL),y)
ext3-objs += acl.o
endif
include $(TOPDIR)/Rules.make
This diff is collapsed.
/*
File: fs/ext3/acl.h
(C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#include <linux/xattr_acl.h>
#define EXT3_ACL_VERSION 0x0001
#define EXT3_ACL_MAX_ENTRIES 32
typedef struct {
__u16 e_tag;
__u16 e_perm;
__u32 e_id;
} ext3_acl_entry;
typedef struct {
__u16 e_tag;
__u16 e_perm;
} ext3_acl_entry_short;
typedef struct {
__u32 a_version;
} ext3_acl_header;
static inline size_t ext3_acl_size(int count)
{
if (count <= 4) {
return sizeof(ext3_acl_header) +
count * sizeof(ext3_acl_entry_short);
} else {
return sizeof(ext3_acl_header) +
4 * sizeof(ext3_acl_entry_short) +
(count - 4) * sizeof(ext3_acl_entry);
}
}
static inline int ext3_acl_count(size_t size)
{
ssize_t s;
size -= sizeof(ext3_acl_header);
s = size - 4 * sizeof(ext3_acl_entry_short);
if (s < 0) {
if (size % sizeof(ext3_acl_entry_short))
return -1;
return size / sizeof(ext3_acl_entry_short);
} else {
if (s % sizeof(ext3_acl_entry))
return -1;
return s / sizeof(ext3_acl_entry) + 4;
}
}
#ifdef CONFIG_EXT3_FS_POSIX_ACL
/* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl
if the ACL has not been cached */
#define EXT3_ACL_NOT_CACHED ((void *)-1)
/* acl.c */
extern int ext3_permission (struct inode *, int);
extern int ext3_permission_locked (struct inode *, int);
extern int ext3_acl_chmod (struct inode *);
extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
extern int init_ext3_acl(void);
extern void exit_ext3_acl(void);
#else /* CONFIG_EXT3_FS_POSIX_ACL */
#include <linux/sched.h>
#define ext3_permission NULL
static inline int
ext3_acl_chmod(struct inode *inode)
{
return 0;
}
static inline int
ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
{
inode->i_mode &= ~current->fs->umask;
return 0;
}
#endif /* CONFIG_EXT3_FS_POSIX_ACL */
......@@ -24,6 +24,7 @@
#include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h>
#include "xattr.h"
#include "acl.h"
/*
* Called when an inode is released. Note that this is different
......@@ -102,5 +103,6 @@ struct inode_operations ext3_file_inode_operations = {
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
.permission = ext3_permission,
};
......@@ -26,6 +26,7 @@
#include <asm/byteorder.h>
#include "xattr.h"
#include "acl.h"
/*
* ialloc.c contains the inodes allocation and deallocation routines
......@@ -423,20 +424,27 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
inode->i_generation = EXT3_SB(sb)->s_next_generation++;
ei->i_state = EXT3_STATE_NEW;
err = ext3_mark_inode_dirty(handle, inode);
if (err) goto fail;
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 {
ext3_debug("allocating inode %lu\n", inode->i_ino);
err = -EDQUOT;
goto fail2;
}
err = ext3_init_acl(handle, inode, dir);
if (err) {
DQUOT_FREE_INODE(inode);
goto fail2;
}
err = ext3_mark_inode_dirty(handle, inode);
if (err) {
ext3_std_error(sb, err);
DQUOT_FREE_INODE(inode);
goto fail2;
}
ext3_debug("allocating inode %lu\n", inode->i_ino);
goto really_out;
fail:
ext3_std_error(sb, err);
......@@ -447,6 +455,12 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
really_out:
brelse(bitmap_bh);
return ret;
fail2:
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return ERR_PTR(err);
}
/* Verify that we are loading a valid orphan from disk */
......
......@@ -34,6 +34,8 @@
#include <linux/string.h>
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include "xattr.h"
#include "acl.h"
/*
* SEARCH_FROM_ZERO forces each block allocation to search from the start
......@@ -2199,7 +2201,11 @@ void ext3_read_inode(struct inode * inode)
struct buffer_head *bh;
int block;
if(ext3_get_inode_loc(inode, &iloc))
#ifdef CONFIG_EXT3_FS_POSIX_ACL
ei->i_acl = EXT3_ACL_NOT_CACHED;
ei->i_default_acl = EXT3_ACL_NOT_CACHED;
#endif
if (ext3_get_inode_loc(inode, &iloc))
goto bad_inode;
bh = iloc.bh;
raw_inode = iloc.raw_inode;
......@@ -2491,13 +2497,8 @@ void ext3_write_inode(struct inode *inode, int wait)
* be freed, so we have a strong guarantee that no future commit will
* leave these blocks visible to the user.)
*
* This is only needed for regular files. rmdir() has its own path, and
* we can never truncate a direcory except on final unlink (at which
* point i_nlink is zero so recovery is easy.)
*
* Called with the BKL.
* Called with inode->sem down.
*/
int ext3_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
......@@ -2517,7 +2518,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
lock_kernel();
if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
if (S_ISREG(inode->i_mode) &&
attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
handle_t *handle;
handle = ext3_journal_start(inode, 3);
......@@ -2542,6 +2544,9 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
if (inode->i_nlink)
ext3_orphan_del(NULL, inode);
if (!rc && (ia_valid & ATTR_MODE))
rc = ext3_acl_chmod(inode);
err_out:
ext3_std_error(inode->i_sb, error);
unlock_kernel();
......
......@@ -37,7 +37,7 @@
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
#include "xattr.h"
#include "acl.h"
/*
* define how far ahead to read directories while searching them.
......@@ -1624,7 +1624,10 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
inode = ext3_new_inode (handle, dir, mode);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, mode, rdev);
init_special_inode(inode, inode->i_mode, rdev);
#ifdef CONFIG_EXT3_FS_XATTR
inode->i_op = &ext3_special_inode_operations;
#endif
err = ext3_add_nondir(handle, dentry, inode);
ext3_mark_inode_dirty(handle, inode);
}
......@@ -2281,17 +2284,21 @@ struct inode_operations ext3_dir_inode_operations = {
.rmdir = ext3_rmdir,
.mknod = ext3_mknod,
.rename = ext3_rename,
.setattr = ext3_setattr,
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
.permission = ext3_permission,
};
struct inode_operations ext3_special_inode_operations = {
.setattr = ext3_setattr,
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
.permission = ext3_permission,
};
......@@ -31,6 +31,7 @@
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
#include "xattr.h"
#include "acl.h"
#ifdef CONFIG_JBD_DEBUG
static int ext3_ro_after; /* Make fs read-only after this many jiffies */
......@@ -428,6 +429,10 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS);
if (!ei)
return NULL;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
ei->i_acl = EXT3_ACL_NOT_CACHED;
ei->i_default_acl = EXT3_ACL_NOT_CACHED;
#endif
return &ei->vfs_inode;
}
......@@ -465,6 +470,26 @@ static void destroy_inodecache(void)
printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
}
#ifdef CONFIG_EXT3_FS_POSIX_ACL
static void ext3_clear_inode(struct inode *inode)
{
if (EXT3_I(inode)->i_acl &&
EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
posix_acl_release(EXT3_I(inode)->i_acl);
EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
}
if (EXT3_I(inode)->i_default_acl &&
EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
posix_acl_release(EXT3_I(inode)->i_default_acl);
EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
}
}
#else
# define ext3_clear_inode NULL
#endif
static struct super_operations ext3_sops = {
.alloc_inode = ext3_alloc_inode,
.destroy_inode = ext3_destroy_inode,
......@@ -479,6 +504,7 @@ static struct super_operations ext3_sops = {
.unlockfs = ext3_unlockfs, /* BKL not held. We take it */
.statfs = ext3_statfs, /* BKL not held. */
.remount_fs = ext3_remount, /* BKL held */
.clear_inode = ext3_clear_inode, /* BKL not needed. */
};
struct dentry *ext3_get_parent(struct dentry *child);
......@@ -559,6 +585,13 @@ static int parse_options (char * options, struct ext3_sb_info *sbi,
else if (!strcmp (this_char, "nouser_xattr"))
clear_opt (sbi->s_mount_opt, XATTR_USER);
else
#endif
#ifdef CONFIG_EXT3_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);
......@@ -1028,6 +1061,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, NO_UID32);
if (def_mount_opts & EXT3_DEFM_XATTR_USER)
set_opt(sbi->s_mount_opt, XATTR_USER);
if (def_mount_opts & EXT3_DEFM_ACL)
set_opt(sbi->s_mount_opt, POSIX_ACL);
if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA)
sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA;
else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED)
......@@ -1046,6 +1081,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
if (!parse_options ((char *) data, sbi, &journal_inum, 0))
goto failed_mount;
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
(EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
......@@ -1735,6 +1773,9 @@ int ext3_remount (struct super_block * sb, int * flags, char * data)
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
ext3_abort(sb, __FUNCTION__, "Abort forced by user");
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
es = sbi->s_es;
ext3_init_journal_params(sbi, sbi->s_journal);
......
......@@ -61,6 +61,7 @@
#include <linux/quotaops.h>
#include <asm/semaphore.h>
#include "xattr.h"
#include "acl.h"
#define EXT3_EA_USER "user."
......@@ -1105,15 +1106,27 @@ init_ext3_xattr(void)
err = ext3_xattr_register(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
if (err)
return err;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
err = init_ext3_acl();
if (err)
goto out;
#endif
ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
sizeof(struct mb_cache_entry) +
sizeof(struct mb_cache_entry_index), 1, 6);
if (!ext3_xattr_cache) {
ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
return -ENOMEM;
err = -ENOMEM;
goto out1;
}
return 0;
out1:
#ifdef CONFIG_EXT3_FS_POSIX_ACL
exit_ext3_acl();
out:
#endif
ext3_xattr_unregister(EXT3_XATTR_INDEX_USER,
&ext3_xattr_user_handler);
return err;
}
void
......@@ -1122,6 +1135,8 @@ exit_ext3_xattr(void)
if (ext3_xattr_cache)
mb_cache_destroy(ext3_xattr_cache);
ext3_xattr_cache = NULL;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
exit_ext3_acl();
#endif
ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
}
......@@ -323,6 +323,7 @@ struct ext3_inode {
#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
......
......@@ -41,6 +41,10 @@ struct ext3_inode_info {
__u32 i_prealloc_count;
#endif
__u32 i_dir_start_lookup;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
struct list_head i_orphan; /* unlinked but open inodes */
......
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