mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 08:02:30 +00:00
c1a198d923
Pull btrfs updates from Chris Mason: "This has our usual assortment of fixes and cleanups, but the biggest change included is Omar Sandoval's free space tree. It's not the default yet, mounting -o space_cache=v2 enables it and sets a readonly compat bit. The tree can actually be deleted and regenerated if there are any problems, but it has held up really well in testing so far. For very large filesystems (30T+) our existing free space caching code can end up taking a huge amount of time during commits. The new tree based code is faster and less work overall to update as the commit progresses. Omar worked on this during the summer and we'll hammer on it in production here at FB over the next few months" * 'for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (73 commits) Btrfs: fix fitrim discarding device area reserved for boot loader's use Btrfs: Check metadata redundancy on balance btrfs: statfs: report zero available if metadata are exhausted btrfs: preallocate path for snapshot creation at ioctl time btrfs: allocate root item at snapshot ioctl time btrfs: do an allocation earlier during snapshot creation btrfs: use smaller type for btrfs_path locks btrfs: use smaller type for btrfs_path lowest_level btrfs: use smaller type for btrfs_path reada btrfs: cleanup, use enum values for btrfs_path reada btrfs: constify static arrays btrfs: constify remaining structs with function pointers btrfs tests: replace whole ops structure for free space tests btrfs: use list_for_each_entry* in backref.c btrfs: use list_for_each_entry_safe in free-space-cache.c btrfs: use list_for_each_entry* in check-integrity.c Btrfs: use linux/sizes.h to represent constants btrfs: cleanup, remove stray return statements btrfs: zero out delayed node upon allocation btrfs: pass proper enum type to start_transaction() ...
166 lines
3.7 KiB
C
166 lines
3.7 KiB
C
/*
|
|
* Copyright (C) 2007 Red Hat. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License v2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 021110-1307, USA.
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/string.h>
|
|
#include <linux/xattr.h>
|
|
#include <linux/posix_acl_xattr.h>
|
|
#include <linux/posix_acl.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "ctree.h"
|
|
#include "btrfs_inode.h"
|
|
#include "xattr.h"
|
|
|
|
struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
|
|
{
|
|
int size;
|
|
const char *name;
|
|
char *value = NULL;
|
|
struct posix_acl *acl;
|
|
|
|
switch (type) {
|
|
case ACL_TYPE_ACCESS:
|
|
name = XATTR_NAME_POSIX_ACL_ACCESS;
|
|
break;
|
|
case ACL_TYPE_DEFAULT:
|
|
name = XATTR_NAME_POSIX_ACL_DEFAULT;
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
size = __btrfs_getxattr(inode, name, "", 0);
|
|
if (size > 0) {
|
|
value = kzalloc(size, GFP_KERNEL);
|
|
if (!value)
|
|
return ERR_PTR(-ENOMEM);
|
|
size = __btrfs_getxattr(inode, name, value, size);
|
|
}
|
|
if (size > 0) {
|
|
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
|
} else if (size == -ENOENT || size == -ENODATA || size == 0) {
|
|
/* FIXME, who returns -ENOENT? I think nobody */
|
|
acl = NULL;
|
|
} else {
|
|
acl = ERR_PTR(-EIO);
|
|
}
|
|
kfree(value);
|
|
|
|
if (!IS_ERR(acl))
|
|
set_cached_acl(inode, type, acl);
|
|
|
|
return acl;
|
|
}
|
|
|
|
/*
|
|
* Needs to be called with fs_mutex held
|
|
*/
|
|
static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
|
|
struct inode *inode, struct posix_acl *acl, int type)
|
|
{
|
|
int ret, size = 0;
|
|
const char *name;
|
|
char *value = NULL;
|
|
|
|
switch (type) {
|
|
case ACL_TYPE_ACCESS:
|
|
name = XATTR_NAME_POSIX_ACL_ACCESS;
|
|
if (acl) {
|
|
ret = posix_acl_equiv_mode(acl, &inode->i_mode);
|
|
if (ret < 0)
|
|
return ret;
|
|
if (ret == 0)
|
|
acl = NULL;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
case ACL_TYPE_DEFAULT:
|
|
if (!S_ISDIR(inode->i_mode))
|
|
return acl ? -EINVAL : 0;
|
|
name = XATTR_NAME_POSIX_ACL_DEFAULT;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (acl) {
|
|
size = posix_acl_xattr_size(acl->a_count);
|
|
value = kmalloc(size, GFP_KERNEL);
|
|
if (!value) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
|
if (ret < 0)
|
|
goto out;
|
|
}
|
|
|
|
ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
|
|
out:
|
|
kfree(value);
|
|
|
|
if (!ret)
|
|
set_cached_acl(inode, type, acl);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|
{
|
|
return __btrfs_set_acl(NULL, inode, acl, type);
|
|
}
|
|
|
|
/*
|
|
* btrfs_init_acl is already generally called under fs_mutex, so the locking
|
|
* stuff has been fixed to work with that. If the locking stuff changes, we
|
|
* need to re-evaluate the acl locking stuff.
|
|
*/
|
|
int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
|
struct inode *inode, struct inode *dir)
|
|
{
|
|
struct posix_acl *default_acl, *acl;
|
|
int ret = 0;
|
|
|
|
/* this happens with subvols */
|
|
if (!dir)
|
|
return 0;
|
|
|
|
ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (default_acl) {
|
|
ret = __btrfs_set_acl(trans, inode, default_acl,
|
|
ACL_TYPE_DEFAULT);
|
|
posix_acl_release(default_acl);
|
|
}
|
|
|
|
if (acl) {
|
|
if (!ret)
|
|
ret = __btrfs_set_acl(trans, inode, acl,
|
|
ACL_TYPE_ACCESS);
|
|
posix_acl_release(acl);
|
|
}
|
|
|
|
if (!default_acl && !acl)
|
|
cache_no_acl(inode);
|
|
return ret;
|
|
}
|