mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
reiserfs: Clean up xattrs when REISERFS_FS_XATTR is unset
The current reiserfs xattr implementation will not clean up old xattr files if files are deleted when REISERFS_FS_XATTR is unset. This results in inaccessible lost files, wasting space. This patch compiles in basic xattr knowledge, such as how to delete them and change ownership for quota tracking. If the file system has never used xattrs, then the operation is quite fast: it returns immediately when it sees there is no .reiserfs_priv directory. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
6dfede6963
commit
a72bdb1cd2
@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o
|
||||
reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
|
||||
super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
|
||||
hashes.o tail_conversion.o journal.o resize.o \
|
||||
item_ops.o ioctl.o procfs.o
|
||||
item_ops.o ioctl.o procfs.o xattr.o
|
||||
|
||||
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
|
||||
reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o
|
||||
reiserfs-objs += xattr_user.o xattr_trusted.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_REISERFS_FS_SECURITY),y)
|
||||
|
@ -50,9 +50,6 @@
|
||||
#define PRIVROOT_NAME ".reiserfs_priv"
|
||||
#define XAROOT_NAME "xattrs"
|
||||
|
||||
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
|
||||
*prefix);
|
||||
|
||||
/* Returns the dentry referring to the root of the extended attribute
|
||||
* directory tree. If it has already been retrieved, it is used. If it
|
||||
* hasn't been created and the flags indicate creation is allowed, we
|
||||
@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
|
||||
return xadir;
|
||||
}
|
||||
|
||||
/* Returns a dentry corresponding to a specific extended attribute file
|
||||
* for the inode. If flags allow, the file is created. Otherwise, a
|
||||
* valid or negative dentry, or an error is returned. */
|
||||
static struct dentry *get_xa_file_dentry(const struct inode *inode,
|
||||
const char *name, int flags)
|
||||
{
|
||||
struct dentry *xadir, *xafile;
|
||||
int err = 0;
|
||||
|
||||
xadir = open_xa_dir(inode, flags);
|
||||
if (IS_ERR(xadir)) {
|
||||
return ERR_CAST(xadir);
|
||||
} else if (!xadir->d_inode) {
|
||||
dput(xadir);
|
||||
return ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
xafile = lookup_one_len(name, xadir, strlen(name));
|
||||
if (IS_ERR(xafile)) {
|
||||
dput(xadir);
|
||||
return ERR_CAST(xafile);
|
||||
}
|
||||
|
||||
if (xafile->d_inode) { /* file exists */
|
||||
if (flags & XATTR_CREATE) {
|
||||
err = -EEXIST;
|
||||
dput(xafile);
|
||||
goto out;
|
||||
}
|
||||
} else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
|
||||
goto out;
|
||||
} else {
|
||||
/* inode->i_mutex is down, so nothing else can try to create
|
||||
* the same xattr */
|
||||
err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
|
||||
0700 | S_IFREG, NULL);
|
||||
|
||||
if (err) {
|
||||
dput(xafile);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
dput(xadir);
|
||||
if (err)
|
||||
xafile = ERR_PTR(err);
|
||||
else if (!xafile->d_inode) {
|
||||
dput(xafile);
|
||||
xafile = ERR_PTR(-ENODATA);
|
||||
}
|
||||
return xafile;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
|
||||
* we need to drop the path before calling the filldir struct. That
|
||||
@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *dir = xadir->d_inode;
|
||||
int err = 0;
|
||||
|
||||
dentry = lookup_one_len(name, xadir, namelen);
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
goto out;
|
||||
} else if (!dentry->d_inode) {
|
||||
err = -ENODATA;
|
||||
goto out_file;
|
||||
}
|
||||
|
||||
/* Skip directories.. */
|
||||
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
goto out_file;
|
||||
|
||||
if (!IS_PRIVATE(dentry->d_inode)) {
|
||||
reiserfs_error(dir->i_sb, "jdm-20003",
|
||||
"OID %08x [%.*s/%.*s] doesn't have "
|
||||
"priv flag set [parent is %sset].",
|
||||
le32_to_cpu(INODE_PKEY(dentry->d_inode)->
|
||||
k_objectid), xadir->d_name.len,
|
||||
xadir->d_name.name, namelen, name,
|
||||
IS_PRIVATE(xadir->d_inode) ? "" :
|
||||
"not ");
|
||||
dput(dentry);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = dir->i_op->unlink(dir, dentry);
|
||||
if (!err)
|
||||
d_delete(dentry);
|
||||
|
||||
out_file:
|
||||
dput(dentry);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The following are side effects of other operations that aren't explicitly
|
||||
* modifying extended attributes. This includes operations such as permissions
|
||||
* or ownership changes, object deletions, etc. */
|
||||
|
||||
static int
|
||||
reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct dentry *xadir = (struct dentry *)buf;
|
||||
|
||||
return __reiserfs_xattr_del(xadir, name, namelen);
|
||||
|
||||
}
|
||||
|
||||
/* This is called w/ inode->i_mutex downed */
|
||||
int reiserfs_delete_xattrs(struct inode *inode)
|
||||
{
|
||||
struct dentry *dir, *root;
|
||||
int err = 0;
|
||||
|
||||
/* Skip out, an xattr has no xattrs associated with it */
|
||||
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
|
||||
return 0;
|
||||
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
dir = open_xa_dir(inode, FL_READONLY);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
if (IS_ERR(dir)) {
|
||||
err = PTR_ERR(dir);
|
||||
goto out;
|
||||
} else if (!dir->d_inode) {
|
||||
dput(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
|
||||
if (err) {
|
||||
unlock_kernel();
|
||||
goto out_dir;
|
||||
}
|
||||
|
||||
/* Leftovers besides . and .. -- that's not good. */
|
||||
if (dir->d_inode->i_nlink <= 2) {
|
||||
root = get_xa_root(inode->i_sb, XATTR_REPLACE);
|
||||
reiserfs_write_lock_xattrs(inode->i_sb);
|
||||
err = vfs_rmdir(root->d_inode, dir);
|
||||
reiserfs_write_unlock_xattrs(inode->i_sb);
|
||||
dput(root);
|
||||
} else {
|
||||
reiserfs_warning(inode->i_sb, "jdm-20006",
|
||||
"Couldn't remove all entries in directory");
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
out_dir:
|
||||
dput(dir);
|
||||
|
||||
out:
|
||||
if (!err)
|
||||
REISERFS_I(inode)->i_flags =
|
||||
REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct reiserfs_chown_buf {
|
||||
struct inode *inode;
|
||||
struct dentry *xadir;
|
||||
struct iattr *attrs;
|
||||
};
|
||||
|
||||
/* XXX: If there is a better way to do this, I'd love to hear about it */
|
||||
static int
|
||||
reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
|
||||
struct dentry *xafile, *xadir = chown_buf->xadir;
|
||||
struct iattr *attrs = chown_buf->attrs;
|
||||
int err = 0;
|
||||
|
||||
xafile = lookup_one_len(name, xadir, namelen);
|
||||
if (IS_ERR(xafile))
|
||||
return PTR_ERR(xafile);
|
||||
else if (!xafile->d_inode) {
|
||||
dput(xafile);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(xafile->d_inode->i_mode))
|
||||
err = notify_change(xafile, attrs);
|
||||
dput(xafile);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
|
||||
{
|
||||
struct dentry *dir;
|
||||
int err = 0;
|
||||
struct reiserfs_chown_buf buf;
|
||||
unsigned int ia_valid = attrs->ia_valid;
|
||||
|
||||
/* Skip out, an xattr has no xattrs associated with it */
|
||||
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
|
||||
return 0;
|
||||
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
dir = open_xa_dir(inode, FL_READONLY);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
if (IS_ERR(dir)) {
|
||||
if (PTR_ERR(dir) != -ENODATA)
|
||||
err = PTR_ERR(dir);
|
||||
goto out;
|
||||
} else if (!dir->d_inode) {
|
||||
dput(dir);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
|
||||
attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
|
||||
buf.xadir = dir;
|
||||
buf.attrs = attrs;
|
||||
buf.inode = inode;
|
||||
|
||||
err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
|
||||
if (err) {
|
||||
unlock_kernel();
|
||||
goto out_dir;
|
||||
}
|
||||
|
||||
err = notify_change(dir, attrs);
|
||||
unlock_kernel();
|
||||
|
||||
out_dir:
|
||||
dput(dir);
|
||||
|
||||
out:
|
||||
attrs->ia_valid = ia_valid;
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
|
||||
*prefix);
|
||||
|
||||
/* Returns a dentry corresponding to a specific extended attribute file
|
||||
* for the inode. If flags allow, the file is created. Otherwise, a
|
||||
* valid or negative dentry, or an error is returned. */
|
||||
static struct dentry *get_xa_file_dentry(const struct inode *inode,
|
||||
const char *name, int flags)
|
||||
{
|
||||
struct dentry *xadir, *xafile;
|
||||
int err = 0;
|
||||
|
||||
xadir = open_xa_dir(inode, flags);
|
||||
if (IS_ERR(xadir)) {
|
||||
return ERR_CAST(xadir);
|
||||
} else if (xadir && !xadir->d_inode) {
|
||||
dput(xadir);
|
||||
return ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
xafile = lookup_one_len(name, xadir, strlen(name));
|
||||
if (IS_ERR(xafile)) {
|
||||
dput(xadir);
|
||||
return ERR_CAST(xafile);
|
||||
}
|
||||
|
||||
if (xafile->d_inode) { /* file exists */
|
||||
if (flags & XATTR_CREATE) {
|
||||
err = -EEXIST;
|
||||
dput(xafile);
|
||||
goto out;
|
||||
}
|
||||
} else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
|
||||
goto out;
|
||||
} else {
|
||||
/* inode->i_mutex is down, so nothing else can try to create
|
||||
* the same xattr */
|
||||
err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
|
||||
0700 | S_IFREG, NULL);
|
||||
|
||||
if (err) {
|
||||
dput(xafile);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
dput(xadir);
|
||||
if (err)
|
||||
xafile = ERR_PTR(err);
|
||||
else if (!xafile->d_inode) {
|
||||
dput(xafile);
|
||||
xafile = ERR_PTR(-ENODATA);
|
||||
}
|
||||
return xafile;
|
||||
}
|
||||
|
||||
/* Internal operations on file data */
|
||||
static inline void reiserfs_put_page(struct page *page)
|
||||
{
|
||||
@ -606,54 +794,10 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
out_dput:
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *dir = xadir->d_inode;
|
||||
int err = 0;
|
||||
|
||||
dentry = lookup_one_len(name, xadir, namelen);
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
goto out;
|
||||
} else if (!dentry->d_inode) {
|
||||
err = -ENODATA;
|
||||
goto out_file;
|
||||
}
|
||||
|
||||
/* Skip directories.. */
|
||||
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
goto out_file;
|
||||
|
||||
if (!IS_PRIVATE(dentry->d_inode)) {
|
||||
reiserfs_error(dir->i_sb, "jdm-20003",
|
||||
"OID %08x [%.*s/%.*s] doesn't have "
|
||||
"priv flag set [parent is %sset].",
|
||||
le32_to_cpu(INODE_PKEY(dentry->d_inode)->
|
||||
k_objectid), xadir->d_name.len,
|
||||
xadir->d_name.name, namelen, name,
|
||||
IS_PRIVATE(xadir->d_inode) ? "" :
|
||||
"not ");
|
||||
dput(dentry);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = dir->i_op->unlink(dir, dentry);
|
||||
if (!err)
|
||||
d_delete(dentry);
|
||||
|
||||
out_file:
|
||||
dput(dentry);
|
||||
|
||||
out:
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -680,151 +824,6 @@ int reiserfs_xattr_del(struct inode *inode, const char *name)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The following are side effects of other operations that aren't explicitly
|
||||
* modifying extended attributes. This includes operations such as permissions
|
||||
* or ownership changes, object deletions, etc. */
|
||||
|
||||
static int
|
||||
reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct dentry *xadir = (struct dentry *)buf;
|
||||
|
||||
return __reiserfs_xattr_del(xadir, name, namelen);
|
||||
|
||||
}
|
||||
|
||||
/* This is called w/ inode->i_mutex downed */
|
||||
int reiserfs_delete_xattrs(struct inode *inode)
|
||||
{
|
||||
struct dentry *dir, *root;
|
||||
int err = 0;
|
||||
|
||||
/* Skip out, an xattr has no xattrs associated with it */
|
||||
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 ||
|
||||
!reiserfs_xattrs(inode->i_sb)) {
|
||||
return 0;
|
||||
}
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
dir = open_xa_dir(inode, FL_READONLY);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
if (IS_ERR(dir)) {
|
||||
err = PTR_ERR(dir);
|
||||
goto out;
|
||||
} else if (!dir->d_inode) {
|
||||
dput(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
|
||||
if (err) {
|
||||
unlock_kernel();
|
||||
goto out_dir;
|
||||
}
|
||||
|
||||
/* Leftovers besides . and .. -- that's not good. */
|
||||
if (dir->d_inode->i_nlink <= 2) {
|
||||
root = get_xa_root(inode->i_sb, XATTR_REPLACE);
|
||||
reiserfs_write_lock_xattrs(inode->i_sb);
|
||||
err = vfs_rmdir(root->d_inode, dir);
|
||||
reiserfs_write_unlock_xattrs(inode->i_sb);
|
||||
dput(root);
|
||||
} else {
|
||||
reiserfs_warning(inode->i_sb, "jdm-20006",
|
||||
"Couldn't remove all entries in directory");
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
out_dir:
|
||||
dput(dir);
|
||||
|
||||
out:
|
||||
if (!err)
|
||||
REISERFS_I(inode)->i_flags =
|
||||
REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct reiserfs_chown_buf {
|
||||
struct inode *inode;
|
||||
struct dentry *xadir;
|
||||
struct iattr *attrs;
|
||||
};
|
||||
|
||||
/* XXX: If there is a better way to do this, I'd love to hear about it */
|
||||
static int
|
||||
reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
|
||||
struct dentry *xafile, *xadir = chown_buf->xadir;
|
||||
struct iattr *attrs = chown_buf->attrs;
|
||||
int err = 0;
|
||||
|
||||
xafile = lookup_one_len(name, xadir, namelen);
|
||||
if (IS_ERR(xafile))
|
||||
return PTR_ERR(xafile);
|
||||
else if (!xafile->d_inode) {
|
||||
dput(xafile);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(xafile->d_inode->i_mode))
|
||||
err = notify_change(xafile, attrs);
|
||||
dput(xafile);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
|
||||
{
|
||||
struct dentry *dir;
|
||||
int err = 0;
|
||||
struct reiserfs_chown_buf buf;
|
||||
unsigned int ia_valid = attrs->ia_valid;
|
||||
|
||||
/* Skip out, an xattr has no xattrs associated with it */
|
||||
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 ||
|
||||
!reiserfs_xattrs(inode->i_sb)) {
|
||||
return 0;
|
||||
}
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
dir = open_xa_dir(inode, FL_READONLY);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
if (IS_ERR(dir)) {
|
||||
if (PTR_ERR(dir) != -ENODATA)
|
||||
err = PTR_ERR(dir);
|
||||
goto out;
|
||||
} else if (!dir->d_inode) {
|
||||
dput(dir);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
|
||||
attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
|
||||
buf.xadir = dir;
|
||||
buf.attrs = attrs;
|
||||
buf.inode = inode;
|
||||
|
||||
err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
|
||||
if (err) {
|
||||
unlock_kernel();
|
||||
goto out_dir;
|
||||
}
|
||||
|
||||
err = notify_change(dir, attrs);
|
||||
unlock_kernel();
|
||||
|
||||
out_dir:
|
||||
dput(dir);
|
||||
|
||||
out:
|
||||
attrs->ia_valid = ia_valid;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Actual operations that are exported to VFS-land */
|
||||
|
||||
/*
|
||||
@ -1101,112 +1100,6 @@ void reiserfs_xattr_unregister_handlers(void)
|
||||
write_unlock(&handler_lock);
|
||||
}
|
||||
|
||||
/* This will catch lookups from the fs root to .reiserfs_priv */
|
||||
static int
|
||||
xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
|
||||
{
|
||||
struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root;
|
||||
if (name->len == priv_root->d_name.len &&
|
||||
name->hash == priv_root->d_name.hash &&
|
||||
!memcmp(name->name, priv_root->d_name.name, name->len)) {
|
||||
return -ENOENT;
|
||||
} else if (q1->len == name->len &&
|
||||
!memcmp(q1->name, name->name, name->len))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dentry_operations xattr_lookup_poison_ops = {
|
||||
.d_compare = xattr_lookup_poison,
|
||||
};
|
||||
|
||||
/* We need to take a copy of the mount flags since things like
|
||||
* MS_RDONLY don't get set until *after* we're called.
|
||||
* mount_flags != mount_options */
|
||||
int reiserfs_xattr_init(struct super_block *s, int mount_flags)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* We need generation numbers to ensure that the oid mapping is correct
|
||||
* v3.5 filesystems don't have them. */
|
||||
if (!old_format_only(s)) {
|
||||
set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
} else if (reiserfs_xattrs_optional(s)) {
|
||||
/* Old format filesystem, but optional xattrs have been enabled
|
||||
* at mount time. Error out. */
|
||||
reiserfs_warning(s, "jdm-20005",
|
||||
"xattrs/ACLs not supported on pre v3.6 "
|
||||
"format filesystem. Failing mount.");
|
||||
err = -EOPNOTSUPP;
|
||||
goto error;
|
||||
} else {
|
||||
/* Old format filesystem, but no optional xattrs have been enabled. This
|
||||
* means we silently disable xattrs on the filesystem. */
|
||||
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
}
|
||||
|
||||
/* If we don't have the privroot located yet - go find it */
|
||||
if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) {
|
||||
struct dentry *dentry;
|
||||
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
|
||||
strlen(PRIVROOT_NAME));
|
||||
if (!IS_ERR(dentry)) {
|
||||
if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
|
||||
struct inode *inode = dentry->d_parent->d_inode;
|
||||
mutex_lock_nested(&inode->i_mutex,
|
||||
I_MUTEX_XATTR);
|
||||
err = inode->i_op->mkdir(inode, dentry, 0700);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (err) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
|
||||
if (dentry && dentry->d_inode)
|
||||
reiserfs_info(s, "Created %s - "
|
||||
"reserved for xattr "
|
||||
"storage.\n",
|
||||
PRIVROOT_NAME);
|
||||
} else if (!dentry->d_inode) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
} else
|
||||
err = PTR_ERR(dentry);
|
||||
|
||||
if (!err && dentry) {
|
||||
s->s_root->d_op = &xattr_lookup_poison_ops;
|
||||
dentry->d_inode->i_flags |= S_PRIVATE;
|
||||
REISERFS_SB(s)->priv_root = dentry;
|
||||
} else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
|
||||
/* If we're read-only it just means that the dir hasn't been
|
||||
* created. Not an error -- just no xattrs on the fs. We'll
|
||||
* check again if we go read-write */
|
||||
reiserfs_warning(s, "jdm-20006",
|
||||
"xattrs/ACLs enabled and couldn't "
|
||||
"find/create .reiserfs_priv. "
|
||||
"Failing mount.");
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
/* This is only nonzero if there was an error initializing the xattr
|
||||
* directory or if there is a condition where we don't support them. */
|
||||
if (err) {
|
||||
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
|
||||
clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
|
||||
}
|
||||
|
||||
/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
|
||||
s->s_flags = s->s_flags & ~MS_POSIXACL;
|
||||
if (reiserfs_posixacl(s))
|
||||
s->s_flags |= MS_POSIXACL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int reiserfs_check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
@ -1239,7 +1132,6 @@ int reiserfs_permission(struct inode *inode, int mask)
|
||||
*/
|
||||
if (IS_PRIVATE(inode))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Stat data v1 doesn't support ACLs.
|
||||
*/
|
||||
@ -1248,3 +1140,138 @@ int reiserfs_permission(struct inode *inode, int mask)
|
||||
else
|
||||
return generic_permission(inode, mask, reiserfs_check_acl);
|
||||
}
|
||||
|
||||
static int create_privroot(struct dentry *dentry)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode = dentry->d_parent->d_inode;
|
||||
mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
|
||||
err = inode->i_op->mkdir(inode, dentry, 0700);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (err) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
|
||||
if (dentry && dentry->d_inode)
|
||||
reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr "
|
||||
"storage.\n", PRIVROOT_NAME);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int xattr_mount_check(struct super_block *s)
|
||||
{
|
||||
/* We need generation numbers to ensure that the oid mapping is correct
|
||||
* v3.5 filesystems don't have them. */
|
||||
if (!old_format_only(s)) {
|
||||
set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
} else if (reiserfs_xattrs_optional(s)) {
|
||||
/* Old format filesystem, but optional xattrs have been enabled
|
||||
* at mount time. Error out. */
|
||||
reiserfs_warning(s, "jdm-20005",
|
||||
"xattrs/ACLs not supported on pre v3.6 "
|
||||
"format filesystem. Failing mount.");
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
/* Old format filesystem, but no optional xattrs have
|
||||
* been enabled. This means we silently disable xattrs
|
||||
* on the filesystem. */
|
||||
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int __init reiserfs_xattr_register_handlers(void) { return 0; }
|
||||
void reiserfs_xattr_unregister_handlers(void) {}
|
||||
#endif
|
||||
|
||||
/* This will catch lookups from the fs root to .reiserfs_priv */
|
||||
static int
|
||||
xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
|
||||
{
|
||||
struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root;
|
||||
if (name->len == priv_root->d_name.len &&
|
||||
name->hash == priv_root->d_name.hash &&
|
||||
!memcmp(name->name, priv_root->d_name.name, name->len)) {
|
||||
return -ENOENT;
|
||||
} else if (q1->len == name->len &&
|
||||
!memcmp(q1->name, name->name, name->len))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dentry_operations xattr_lookup_poison_ops = {
|
||||
.d_compare = xattr_lookup_poison,
|
||||
};
|
||||
|
||||
/* We need to take a copy of the mount flags since things like
|
||||
* MS_RDONLY don't get set until *after* we're called.
|
||||
* mount_flags != mount_options */
|
||||
int reiserfs_xattr_init(struct super_block *s, int mount_flags)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
err = xattr_mount_check(s);
|
||||
if (err)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
/* If we don't have the privroot located yet - go find it */
|
||||
if (!REISERFS_SB(s)->priv_root) {
|
||||
struct dentry *dentry;
|
||||
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
|
||||
strlen(PRIVROOT_NAME));
|
||||
if (!IS_ERR(dentry)) {
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
if (!(mount_flags & MS_RDONLY) && !dentry->d_inode)
|
||||
err = create_privroot(dentry);
|
||||
#endif
|
||||
if (!dentry->d_inode) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
} else
|
||||
err = PTR_ERR(dentry);
|
||||
|
||||
if (!err && dentry) {
|
||||
s->s_root->d_op = &xattr_lookup_poison_ops;
|
||||
dentry->d_inode->i_flags |= S_PRIVATE;
|
||||
REISERFS_SB(s)->priv_root = dentry;
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
/* xattrs are unavailable */
|
||||
} else if (!(mount_flags & MS_RDONLY)) {
|
||||
/* If we're read-only it just means that the dir
|
||||
* hasn't been created. Not an error -- just no
|
||||
* xattrs on the fs. We'll check again if we
|
||||
* go read-write */
|
||||
reiserfs_warning(s, "jdm-20006",
|
||||
"xattrs/ACLs enabled and couldn't "
|
||||
"find/create .reiserfs_priv. "
|
||||
"Failing mount.");
|
||||
err = -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
error:
|
||||
if (err) {
|
||||
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
||||
clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
|
||||
clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
|
||||
s->s_flags = s->s_flags & ~MS_POSIXACL;
|
||||
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
|
||||
if (reiserfs_posixacl(s))
|
||||
s->s_flags |= MS_POSIXACL;
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -402,8 +402,8 @@ struct reiserfs_sb_info {
|
||||
int reserved_blocks; /* amount of blocks reserved for further allocations */
|
||||
spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
|
||||
struct dentry *priv_root; /* root of /.reiserfs_priv */
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
struct rw_semaphore xattr_dir_sem;
|
||||
#endif
|
||||
int j_errno;
|
||||
|
@ -43,6 +43,12 @@ struct reiserfs_xattr_handler {
|
||||
struct list_head handlers;
|
||||
};
|
||||
|
||||
int reiserfs_xattr_register_handlers(void) __init;
|
||||
void reiserfs_xattr_unregister_handlers(void);
|
||||
int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
|
||||
int reiserfs_delete_xattrs(struct inode *inode);
|
||||
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
|
||||
ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
|
||||
@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
int reiserfs_removexattr(struct dentry *dentry, const char *name);
|
||||
int reiserfs_delete_xattrs(struct inode *inode);
|
||||
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
|
||||
int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
|
||||
int reiserfs_permission(struct inode *inode, int mask);
|
||||
|
||||
int reiserfs_xattr_del(struct inode *, const char *);
|
||||
@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler user_handler;
|
||||
extern struct reiserfs_xattr_handler trusted_handler;
|
||||
extern struct reiserfs_xattr_handler security_handler;
|
||||
|
||||
int reiserfs_xattr_register_handlers(void) __init;
|
||||
void reiserfs_xattr_unregister_handlers(void);
|
||||
|
||||
static inline void reiserfs_write_lock_xattrs(struct super_block *sb)
|
||||
{
|
||||
down_write(&REISERFS_XATTR_DIR_SEM(sb));
|
||||
@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
|
||||
|
||||
#define reiserfs_permission NULL
|
||||
|
||||
#define reiserfs_xattr_register_handlers() 0
|
||||
#define reiserfs_xattr_unregister_handlers()
|
||||
|
||||
static inline int reiserfs_delete_xattrs(struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
static inline int reiserfs_chown_xattrs(struct inode *inode,
|
||||
struct iattr *attrs)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags)
|
||||
{
|
||||
sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
|
||||
return 0;
|
||||
};
|
||||
static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user