X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext3%2Facl.c;h=1e5038d9a01b9f469015b83f8ee7eb07a9abf8f8;hb=refs%2Fheads%2Fvserver;hp=7fd70c88e932251c3ba75517de216c67f5fe7ef8;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 7fd70c88e..1e5038d9a 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -89,8 +90,8 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) size_t n; *size = ext3_acl_size(acl->a_count); - ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) + - acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL); + ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count * + sizeof(ext3_acl_entry), GFP_KERNEL); if (!ext_acl) return ERR_PTR(-ENOMEM); ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); @@ -152,7 +153,7 @@ ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, /* * Inode operation get_posix_acl(). * - * inode->i_sem: don't care + * inode->i_mutex: don't care */ static struct posix_acl * ext3_get_acl(struct inode *inode, int type) @@ -164,7 +165,7 @@ ext3_get_acl(struct inode *inode, int type) int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; + return NULL; switch(type) { case ACL_TYPE_ACCESS: @@ -197,8 +198,7 @@ ext3_get_acl(struct inode *inode, int type) acl = NULL; else acl = ERR_PTR(retval); - if (value) - kfree(value); + kfree(value); if (!IS_ERR(acl)) { switch(type) { @@ -217,7 +217,7 @@ ext3_get_acl(struct inode *inode, int type) /* * Set the access or default ACL of an inode. * - * inode->i_sem: down unless called from ext3_new_inode + * inode->i_mutex: down unless called from ext3_new_inode */ static int ext3_set_acl(handle_t *handle, struct inode *inode, int type, @@ -226,7 +226,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct ext3_inode_info *ei = EXT3_I(inode); int name_index; void *value = NULL; - size_t size; + size_t size = 0; int error; if (S_ISLNK(inode->i_mode)) @@ -258,9 +258,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, default: return -EINVAL; } - if (acl) { - if (acl->a_count > EXT3_ACL_MAX_ENTRIES) - return -EINVAL; + if (acl) { value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); @@ -269,8 +267,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); - if (value) - kfree(value); + kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: @@ -285,67 +282,33 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -/* - * Inode operation permission(). - * - * inode->i_sem: don't care - */ -int -ext3_permission(struct inode *inode, int mask, struct nameidata *nd) +static int +ext3_check_acl(struct inode *inode, int mask) { - int mode = inode->i_mode; - - /* Nobody gets write access to a read-only fs */ - if ((mask & MAY_WRITE) && IS_RDONLY(inode) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - return -EROFS; - /* Nobody gets write access to an immutable file */ - if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) - return -EACCES; - if (current->fsuid == inode->i_uid) { - mode >>= 6; - } else if (test_opt(inode->i_sb, POSIX_ACL)) { - struct posix_acl *acl; - - /* The access ACL cannot grant access if the group class - permission bits don't contain all requested permissions. */ - if (((mode >> 3) & mask & S_IRWXO) != mask) - goto check_groups; - acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); - if (acl) { - int error = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - if (error == -EACCES) - goto check_capabilities; - return error; - } else - goto check_groups; - } else { -check_groups: - if (in_group_p(inode->i_gid)) - mode >>= 3; + struct posix_acl *acl = ext3_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); + return error; } - if ((mode & mask & S_IRWXO) == mask) - return 0; -check_capabilities: - /* Allowed to override Discretionary Access Control? */ - if (!(mask & MAY_EXEC) || - (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) - if (capable(CAP_DAC_OVERRIDE)) - return 0; - /* Read and search granted if capable(CAP_DAC_READ_SEARCH) */ - if (capable(CAP_DAC_READ_SEARCH) && ((mask == MAY_READ) || - (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))) - return 0; - return -EACCES; + return -EAGAIN; +} + +int +ext3_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, ext3_check_acl); } /* * Initialize the ACLs of a new inode. Called from ext3_new_inode. * - * dir->i_sem: down - * inode->i_sem: up (access to inode is still exclusive) + * 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) @@ -406,7 +369,7 @@ cleanup: * for directories) are added. There are no more bits available in the * file mode. * - * inode->i_sem: down + * inode->i_mutex: down */ int ext3_acl_chmod(struct inode *inode) @@ -428,8 +391,11 @@ ext3_acl_chmod(struct inode *inode) error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) { handle_t *handle; + int retries = 0; - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); + 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); @@ -437,6 +403,9 @@ ext3_acl_chmod(struct inode *inode) } error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); ext3_journal_stop(handle); + if (error == -ENOSPC && + ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; } out: posix_acl_release(clone); @@ -447,28 +416,28 @@ out: * Extended attribute handlers */ static size_t -ext3_xattr_list_acl_access(char *list, struct inode *inode, - const char *name, int name_len) +ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, + const char *name, size_t name_len) { - const size_t size = sizeof(XATTR_NAME_ACL_ACCESS); + const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; - if (list) - memcpy(list, XATTR_NAME_ACL_ACCESS, size); + if (list && size <= list_len) + memcpy(list, POSIX_ACL_XATTR_ACCESS, size); return size; } static size_t -ext3_xattr_list_acl_default(char *list, struct inode *inode, - const char *name, int name_len) +ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, + const char *name, size_t name_len) { - const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT); + const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; - if (list) - memcpy(list, XATTR_NAME_ACL_DEFAULT, size); + if (list && size <= list_len) + memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); return size; } @@ -516,7 +485,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, { handle_t *handle; struct posix_acl *acl; - int error; + int error, retries = 0; if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; @@ -535,11 +504,14 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, } else acl = NULL; - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); +retry: + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); error = ext3_set_acl(handle, inode, type, acl); ext3_journal_stop(handle); + if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; release_and_out: posix_acl_release(acl); @@ -564,45 +536,16 @@ ext3_xattr_set_acl_default(struct inode *inode, const char *name, return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); } -struct ext3_xattr_handler ext3_xattr_acl_access_handler = { - .prefix = XATTR_NAME_ACL_ACCESS, +struct xattr_handler ext3_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, .list = ext3_xattr_list_acl_access, .get = ext3_xattr_get_acl_access, .set = ext3_xattr_set_acl_access, }; -struct ext3_xattr_handler ext3_xattr_acl_default_handler = { - .prefix = XATTR_NAME_ACL_DEFAULT, +struct xattr_handler ext3_xattr_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, .list = ext3_xattr_list_acl_default, .get = ext3_xattr_get_acl_default, .set = ext3_xattr_set_acl_default, }; - -void -exit_ext3_acl(void) -{ - ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS, - &ext3_xattr_acl_access_handler); - ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT, - &ext3_xattr_acl_default_handler); -} - -int __init -init_ext3_acl(void) -{ - int error; - - error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS, - &ext3_xattr_acl_access_handler); - if (error) - goto fail; - error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT, - &ext3_xattr_acl_default_handler); - if (error) - goto fail; - return 0; - -fail: - exit_ext3_acl(); - return error; -}