Commit 0b1a6a8c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reiserfs: xattr support

From: Chris Mason <mason@suse.com>

From: jeffm@suse.com

reiserfs support for xattrs
parent 06803e35
...@@ -244,6 +244,16 @@ config REISERFS_PROC_INFO ...@@ -244,6 +244,16 @@ config REISERFS_PROC_INFO
Almost everyone but ReiserFS developers and people fine-tuning Almost everyone but ReiserFS developers and people fine-tuning
reiserfs or tracing problems should say N. reiserfs or tracing problems should say N.
config REISERFS_FS_XATTR
bool "ReiserFS extended attributes"
depends on REISERFS_FS
help
Extended attributes are name:value pairs associated with inodes by
the kernel or by users (see the attr(5) manual page, or visit
<http://acl.bestbits.at/> for details).
If unsure, say N.
config JFS_FS config JFS_FS
tristate "JFS filesystem support" tristate "JFS filesystem support"
select NLS select NLS
......
...@@ -9,6 +9,10 @@ reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ ...@@ -9,6 +9,10 @@ reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
hashes.o tail_conversion.o journal.o resize.o \ hashes.o tail_conversion.o journal.o resize.o \
item_ops.o ioctl.o procfs.o item_ops.o ioctl.o procfs.o
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
reiserfs-objs += xattr.o xattr_user.o
endif
# gcc -O2 (the kernel default) is overaggressive on ppc32 when many inline # gcc -O2 (the kernel default) is overaggressive on ppc32 when many inline
# functions are used. This causes the compiler to advance the stack # functions are used. This causes the compiler to advance the stack
# pointer out of the available stack space, corrupting kernel space, # pointer out of the available stack space, corrupting kernel space,
......
...@@ -115,6 +115,17 @@ static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldi ...@@ -115,6 +115,17 @@ static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldi
/* too big to send back to VFS */ /* too big to send back to VFS */
continue ; continue ;
} }
/* Ignore the .reiserfs_priv entry */
if (reiserfs_xattrs (inode->i_sb) &&
!old_format_only(inode->i_sb) &&
filp->f_dentry == inode->i_sb->s_root &&
REISERFS_SB(inode->i_sb)->priv_root &&
REISERFS_SB(inode->i_sb)->priv_root->d_inode &&
deh_objectid(deh) == le32_to_cpu (INODE_PKEY(REISERFS_SB(inode->i_sb)->priv_root->d_inode)->k_objectid)) {
continue;
}
d_off = deh_offset (deh); d_off = deh_offset (deh);
filp->f_pos = d_off ; filp->f_pos = d_off ;
d_ino = deh_objectid (deh); d_ino = deh_objectid (deh);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
...@@ -97,51 +98,6 @@ static int reiserfs_sync_file( ...@@ -97,51 +98,6 @@ static int reiserfs_sync_file(
return ( n_err < 0 ) ? -EIO : 0; return ( n_err < 0 ) ? -EIO : 0;
} }
static int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
struct inode *inode = dentry->d_inode ;
int error ;
reiserfs_write_lock(inode->i_sb);
if (attr->ia_valid & ATTR_SIZE) {
/* version 2 items will be caught by the s_maxbytes check
** done for us in vmtruncate
*/
if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
attr->ia_size > MAX_NON_LFS) {
error = -EFBIG ;
goto out;
}
/* fill in hole pointers in the expanding truncate case. */
if (attr->ia_size > inode->i_size) {
error = generic_cont_expand(inode, attr->ia_size) ;
if (REISERFS_I(inode)->i_prealloc_count > 0) {
struct reiserfs_transaction_handle th ;
/* we're changing at most 2 bitmaps, inode + super */
journal_begin(&th, inode->i_sb, 4) ;
reiserfs_discard_prealloc (&th, inode);
journal_end(&th, inode->i_sb, 4) ;
}
if (error)
goto out;
}
}
if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
(get_inode_sd_version (inode) == STAT_DATA_V1)) {
/* stat data of format v3.5 has 16 bit uid and gid */
error = -EINVAL;
goto out;
}
error = inode_change_ok(inode, attr) ;
if (!error)
inode_setattr(inode, attr) ;
out:
reiserfs_write_unlock(inode->i_sb);
return error ;
}
/* I really do not want to play with memory shortage right now, so /* I really do not want to play with memory shortage right now, so
to simplify the code, we are not going to write more than this much pages at to simplify the code, we are not going to write more than this much pages at
a time. This still should considerably improve performance compared to 4k a time. This still should considerably improve performance compared to 4k
...@@ -1321,6 +1277,11 @@ struct file_operations reiserfs_file_operations = { ...@@ -1321,6 +1277,11 @@ struct file_operations reiserfs_file_operations = {
struct inode_operations reiserfs_file_inode_operations = { struct inode_operations reiserfs_file_inode_operations = {
.truncate = reiserfs_vfs_truncate_file, .truncate = reiserfs_vfs_truncate_file,
.setattr = reiserfs_setattr, .setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
.listxattr = reiserfs_listxattr,
.removexattr = reiserfs_removexattr,
.permission = reiserfs_permission,
}; };
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/highmem.h> #include <linux/highmem.h>
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mpage.h> #include <linux/mpage.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/quotaops.h>
extern int reiserfs_default_io_size; /* default io size devuned in super.c */ extern int reiserfs_default_io_size; /* default io size devuned in super.c */
...@@ -40,6 +42,8 @@ void reiserfs_delete_inode (struct inode * inode) ...@@ -40,6 +42,8 @@ void reiserfs_delete_inode (struct inode * inode)
if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */ if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
down (&inode->i_sem); down (&inode->i_sem);
reiserfs_delete_xattrs (inode);
journal_begin(&th, inode->i_sb, jbegin_count) ; journal_begin(&th, inode->i_sb, jbegin_count) ;
reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(inode) ;
...@@ -1053,10 +1057,11 @@ static void init_inode (struct inode * inode, struct path * path) ...@@ -1053,10 +1057,11 @@ static void init_inode (struct inode * inode, struct path * path)
inode->i_op = &reiserfs_dir_inode_operations; inode->i_op = &reiserfs_dir_inode_operations;
inode->i_fop = &reiserfs_dir_operations; inode->i_fop = &reiserfs_dir_operations;
} else if (S_ISLNK (inode->i_mode)) { } else if (S_ISLNK (inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations; inode->i_op = &reiserfs_symlink_inode_operations;
inode->i_mapping->a_ops = &reiserfs_address_space_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations;
} else { } else {
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_op = &reiserfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
} }
} }
...@@ -2509,6 +2514,64 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, ...@@ -2509,6 +2514,64 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
} }
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
struct inode *inode = dentry->d_inode ;
int error ;
unsigned int ia_valid = attr->ia_valid;
reiserfs_write_lock(inode->i_sb);
if (attr->ia_valid & ATTR_SIZE) {
/* version 2 items will be caught by the s_maxbytes check
** done for us in vmtruncate
*/
if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
attr->ia_size > MAX_NON_LFS) {
error = -EFBIG ;
goto out;
}
/* fill in hole pointers in the expanding truncate case. */
if (attr->ia_size > inode->i_size) {
error = generic_cont_expand(inode, attr->ia_size) ;
if (REISERFS_I(inode)->i_prealloc_count > 0) {
struct reiserfs_transaction_handle th ;
/* we're changing at most 2 bitmaps, inode + super */
journal_begin(&th, inode->i_sb, 4) ;
reiserfs_discard_prealloc (&th, inode);
journal_end(&th, inode->i_sb, 4) ;
}
if (error)
goto out;
}
}
if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
(get_inode_sd_version (inode) == STAT_DATA_V1)) {
/* stat data of format v3.5 has 16 bit uid and gid */
error = -EINVAL;
goto out;
}
error = inode_change_ok(inode, attr) ;
if (!error) {
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
error = reiserfs_chown_xattrs (inode, attr);
if (!error)
error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
}
if (!error)
inode_setattr(inode, attr) ;
}
out:
reiserfs_write_unlock(inode->i_sb);
return error ;
}
struct address_space_operations reiserfs_address_space_operations = { struct address_space_operations reiserfs_address_space_operations = {
.writepage = reiserfs_writepage, .writepage = reiserfs_writepage,
.readpage = reiserfs_readpage, .readpage = reiserfs_readpage,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
...@@ -331,11 +332,24 @@ static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dent ...@@ -331,11 +332,24 @@ static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dent
retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path_to_entry, &de); retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path_to_entry, &de);
pathrelse (&path_to_entry); pathrelse (&path_to_entry);
if (retval == NAME_FOUND) { if (retval == NAME_FOUND) {
/* Hide the .reiserfs_priv directory */
if (reiserfs_xattrs (dir->i_sb) &&
!old_format_only(dir->i_sb) &&
REISERFS_SB(dir->i_sb)->priv_root &&
REISERFS_SB(dir->i_sb)->priv_root->d_inode &&
de.de_objectid == le32_to_cpu (INODE_PKEY(REISERFS_SB(dir->i_sb)->priv_root->d_inode)->k_objectid)) {
return ERR_PTR (-EACCES);
}
inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id)); inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
if (!inode || IS_ERR(inode)) { if (!inode || IS_ERR(inode)) {
reiserfs_write_unlock(dir->i_sb); reiserfs_write_unlock(dir->i_sb);
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
} }
/* Propogate the priv_object flag so we know we're in the priv tree */
if (is_reiserfs_priv_object (dir))
REISERFS_I(inode)->i_flags |= i_priv_object;
} }
reiserfs_write_unlock(dir->i_sb); reiserfs_write_unlock(dir->i_sb);
if ( retval == IO_ERROR ) { if ( retval == IO_ERROR ) {
...@@ -630,6 +644,7 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, ...@@ -630,6 +644,7 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode,
goto out_failed; goto out_failed;
} }
inode->i_op = &reiserfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, rdev) ; init_special_inode(inode, inode->i_mode, rdev) ;
//FIXME: needed for block and char devices only //FIXME: needed for block and char devices only
...@@ -942,7 +957,7 @@ static int reiserfs_symlink (struct inode * parent_dir, ...@@ -942,7 +957,7 @@ static int reiserfs_symlink (struct inode * parent_dir,
reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(inode) ;
reiserfs_update_inode_transaction(parent_dir) ; reiserfs_update_inode_transaction(parent_dir) ;
inode->i_op = &page_symlink_inode_operations; inode->i_op = &reiserfs_symlink_inode_operations;
inode->i_mapping->a_ops = &reiserfs_address_space_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations;
// must be sure this inode is written with this transaction // must be sure this inode is written with this transaction
...@@ -1318,5 +1333,42 @@ struct inode_operations reiserfs_dir_inode_operations = { ...@@ -1318,5 +1333,42 @@ struct inode_operations reiserfs_dir_inode_operations = {
.rmdir = reiserfs_rmdir, .rmdir = reiserfs_rmdir,
.mknod = reiserfs_mknod, .mknod = reiserfs_mknod,
.rename = reiserfs_rename, .rename = reiserfs_rename,
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
.listxattr = reiserfs_listxattr,
.removexattr = reiserfs_removexattr,
.permission = reiserfs_permission,
};
/*
* symlink operations.. same as page_symlink_inode_operations, with xattr
* stuff added
*/
struct inode_operations reiserfs_symlink_inode_operations = {
.readlink = page_readlink,
.follow_link = page_follow_link,
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
.listxattr = reiserfs_listxattr,
.removexattr = reiserfs_removexattr,
.permission = reiserfs_permission,
}; };
/*
* special file operations.. just xattr/acl stuff
*/
struct inode_operations reiserfs_special_inode_operations = {
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
.listxattr = reiserfs_listxattr,
.removexattr = reiserfs_removexattr,
.permission = reiserfs_permission,
};
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
...@@ -357,7 +358,17 @@ static void reiserfs_put_super (struct super_block * s) ...@@ -357,7 +358,17 @@ static void reiserfs_put_super (struct super_block * s)
{ {
int i; int i;
struct reiserfs_transaction_handle th ; struct reiserfs_transaction_handle th ;
if (REISERFS_SB(s)->xattr_root) {
d_invalidate (REISERFS_SB(s)->xattr_root);
dput (REISERFS_SB(s)->xattr_root);
}
if (REISERFS_SB(s)->priv_root) {
d_invalidate (REISERFS_SB(s)->priv_root);
dput (REISERFS_SB(s)->priv_root);
}
/* change file system state to current state if it was mounted with read-write permissions */ /* change file system state to current state if it was mounted with read-write permissions */
if (!(s->s_flags & MS_RDONLY)) { if (!(s->s_flags & MS_RDONLY)) {
journal_begin(&th, s, 10) ; journal_begin(&th, s, 10) ;
...@@ -669,6 +680,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st ...@@ -669,6 +680,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
{"conv", 0, 0, 1<<REISERFS_CONVERT, 0}, {"conv", 0, 0, 1<<REISERFS_CONVERT, 0},
{"attrs", 0, 0, 1<<REISERFS_ATTRS, 0}, {"attrs", 0, 0, 1<<REISERFS_ATTRS, 0},
{"noattrs", 0, 0, 0, 1<<REISERFS_ATTRS}, {"noattrs", 0, 0, 0, 1<<REISERFS_ATTRS},
{"user_xattr", 0, 0, 1<<REISERFS_XATTRS_USER, 0},
{"nouser_xattr", 0, 0, 0, 1<<REISERFS_XATTRS_USER},
{"nolog", 0, 0, 0, 0}, /* This is unsupported */ {"nolog", 0, 0, 0, 0}, /* This is unsupported */
{"replayonly", 0, 0, 1<<REPLAYONLY, 0}, {"replayonly", 0, 0, 1<<REPLAYONLY, 0},
{"block-allocator", 'a', balloc, 0, 0}, {"block-allocator", 'a', balloc, 0, 0},
...@@ -813,6 +826,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -813,6 +826,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
safe_mask |= 1 << REISERFS_HASHED_RELOCATION; safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
safe_mask |= 1 << REISERFS_TEST4; safe_mask |= 1 << REISERFS_TEST4;
safe_mask |= 1 << REISERFS_ATTRS; safe_mask |= 1 << REISERFS_ATTRS;
safe_mask |= 1 << REISERFS_XATTRS_USER;
/* Update the bitmask, taking care to keep /* Update the bitmask, taking care to keep
* the bits we're not allowed to change here */ * the bits we're not allowed to change here */
...@@ -836,6 +850,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -836,6 +850,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
} }
if (*mount_flags & MS_RDONLY) { if (*mount_flags & MS_RDONLY) {
reiserfs_xattr_init (s, *mount_flags);
/* remount read-only */ /* remount read-only */
if (s->s_flags & MS_RDONLY) if (s->s_flags & MS_RDONLY)
/* it is read-only already */ /* it is read-only already */
...@@ -852,8 +867,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -852,8 +867,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
} else { } else {
/* remount read-write */ /* remount read-write */
if (!(s->s_flags & MS_RDONLY)) if (!(s->s_flags & MS_RDONLY)) {
reiserfs_xattr_init (s, *mount_flags);
return 0; /* We are read-write already */ return 0; /* We are read-write already */
}
handle_data_mode(s, mount_options); handle_data_mode(s, mount_options);
REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ; REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
...@@ -874,8 +891,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -874,8 +891,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
journal_end(&th, s, 10) ; journal_end(&th, s, 10) ;
s->s_dirt = 0; s->s_dirt = 0;
if (!( *mount_flags & MS_RDONLY ) ) if (!( *mount_flags & MS_RDONLY ) ) {
finish_unfinished( s ); finish_unfinished( s );
reiserfs_xattr_init (s, *mount_flags);
}
return 0; return 0;
} }
...@@ -1305,6 +1324,8 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) ...@@ -1305,6 +1324,8 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
REISERFS_SB(s)->s_alloc_options.preallocmin = 4; REISERFS_SB(s)->s_alloc_options.preallocmin = 4;
/* Preallocate by 16 blocks (17-1) at once */ /* Preallocate by 16 blocks (17-1) at once */
REISERFS_SB(s)->s_alloc_options.preallocsize = 17; REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
/* Initialize the rwsem for xattr dir */
init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
jdev_name = NULL; jdev_name = NULL;
if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) { if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) {
...@@ -1449,13 +1470,25 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) ...@@ -1449,13 +1470,25 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
journal_end(&th, s, 1) ; journal_end(&th, s, 1) ;
if (reiserfs_xattr_init (s, s->s_flags)) {
dput (s->s_root);
s->s_root = NULL;
goto error;
}
/* look for files which were to be removed in previous session */ /* look for files which were to be removed in previous session */
finish_unfinished (s); finish_unfinished (s);
} else { } else {
if ( old_format_only(s) && !silent) { if ( old_format_only(s) && !silent) {
reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; reiserfs_warning("reiserfs: using 3.5.x disk format\n") ;
} }
if (reiserfs_xattr_init (s, s->s_flags)) {
dput (s->s_root);
s->s_root = NULL;
goto error;
}
} }
// mark hash in super block: it could be unset. overwrite should be ok // mark hash in super block: it could be unset. overwrite should be ok
set_sb_hash_function_code( rs, function2code(sbi->s_hash_function ) ); set_sb_hash_function_code( rs, function2code(sbi->s_hash_function ) );
...@@ -1523,6 +1556,9 @@ init_reiserfs_fs ( void ) ...@@ -1523,6 +1556,9 @@ init_reiserfs_fs ( void )
return ret; return ret;
} }
if ((ret = reiserfs_xattr_register_handlers ()))
goto failed_reiserfs_xattr_register_handlers;
reiserfs_proc_info_global_init (); reiserfs_proc_info_global_init ();
reiserfs_proc_register_global ("version", reiserfs_global_version_in_proc); reiserfs_proc_register_global ("version", reiserfs_global_version_in_proc);
...@@ -1532,6 +1568,9 @@ init_reiserfs_fs ( void ) ...@@ -1532,6 +1568,9 @@ init_reiserfs_fs ( void )
return 0; return 0;
} }
reiserfs_xattr_unregister_handlers ();
failed_reiserfs_xattr_register_handlers:
reiserfs_proc_unregister_global ("version"); reiserfs_proc_unregister_global ("version");
reiserfs_proc_info_global_done (); reiserfs_proc_info_global_done ();
destroy_inodecache (); destroy_inodecache ();
...@@ -1542,6 +1581,7 @@ init_reiserfs_fs ( void ) ...@@ -1542,6 +1581,7 @@ init_reiserfs_fs ( void )
static void __exit static void __exit
exit_reiserfs_fs ( void ) exit_reiserfs_fs ( void )
{ {
reiserfs_xattr_unregister_handlers ();
reiserfs_proc_unregister_global ("version"); reiserfs_proc_unregister_global ("version");
reiserfs_proc_info_global_done (); reiserfs_proc_info_global_done ();
unregister_filesystem (& reiserfs_fs_type); unregister_filesystem (& reiserfs_fs_type);
......
/*
* linux/fs/reiserfs/xattr.c
*
* Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com>
*
*/
/*
* In order to implement EAs in a clean, backwards compatible manner,
* they are implemented as files in a "private" directory.
* Each EA is in it's own file, with the directory layout like so (/ is assumed
* to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory,
* directories named using the capital-hex form of the objectid and
* generation number are used. Inside each directory are individual files
* named with the name of the extended attribute.
*
* So, for objectid 12648430, we could have:
* /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type
* .. or similar.
*
* The file contents are the text of the EA. The size is known based on the
* stat data describing the file.
*
*/
#include <linux/reiserfs_fs.h>
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <linux/mbcache.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <linux/smp_lock.h>
#include <linux/stat.h>
#include <asm/semaphore.h>
#define FL_READONLY 128
#define FL_DIR_SEM_HELD 256
#define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs"
static struct reiserfs_xattr_handler *find_xattr_handler_prefix (const char *prefix);
static struct dentry *
create_xa_root (struct super_block *sb)
{
struct dentry *privroot = dget (REISERFS_SB(sb)->priv_root);
struct dentry *xaroot;
/* This needs to be created at mount-time */
if (!privroot)
return ERR_PTR(-EOPNOTSUPP);
xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));
if (IS_ERR (xaroot)) {
goto out;
} else if (!xaroot->d_inode) {
int err;
down (&privroot->d_inode->i_sem);
err = privroot->d_inode->i_op->mkdir (privroot->d_inode, xaroot, 0700);
up (&privroot->d_inode->i_sem);
if (err) {
dput (xaroot);
dput (privroot);
return ERR_PTR (err);
}
REISERFS_SB(sb)->xattr_root = dget (xaroot);
}
out:
dput (privroot);
return xaroot;
}
/* This will return a dentry, or error, refering to the xa root directory.
* If the xa root doesn't exist yet, the dentry will be returned without
* an associated inode. This dentry can be used with ->mkdir to create
* the xa directory. */
static struct dentry *
__get_xa_root (struct super_block *s)
{
struct dentry *privroot = dget (REISERFS_SB(s)->priv_root);
struct dentry *xaroot = NULL;
if (IS_ERR (privroot) || !privroot)
return privroot;
xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));
if (IS_ERR (xaroot)) {
goto out;
} else if (!xaroot->d_inode) {
dput (xaroot);
xaroot = NULL;
goto out;
}
REISERFS_SB(s)->xattr_root = dget (xaroot);
out:
dput (privroot);
return xaroot;
}
/* Returns the dentry (or NULL) referring to the root of the extended
* attribute directory tree. If it has already been retreived, it is used.
* Otherwise, we attempt to retreive it from disk. It may also return
* a pointer-encoded error.
*/
static inline struct dentry *
get_xa_root (struct super_block *s)
{
struct dentry *dentry = dget (REISERFS_SB(s)->xattr_root);
if (!dentry)
dentry = __get_xa_root (s);
return dentry;
}
/* Opens the directory corresponding to the inode's extended attribute store.
* If flags allow, the tree to the directory may be created. If creation is
* prohibited, -ENODATA is returned. */
static struct dentry *
open_xa_dir (const struct inode *inode, int flags)
{
struct dentry *xaroot, *xadir;
char namebuf[17];
xaroot = get_xa_root (inode->i_sb);
if (IS_ERR (xaroot)) {
return xaroot;
} else if (!xaroot) {
if (flags == 0 || flags & XATTR_CREATE) {
xaroot = create_xa_root (inode->i_sb);
if (IS_ERR (xaroot))
return xaroot;
}
if (!xaroot)
return ERR_PTR (-ENODATA);
}
/* ok, we have xaroot open */
snprintf (namebuf, sizeof (namebuf), "%X.%X",
le32_to_cpu (INODE_PKEY (inode)->k_objectid),
inode->i_generation);
xadir = lookup_one_len (namebuf, xaroot, strlen (namebuf));
if (IS_ERR (xadir)) {
dput (xaroot);
return xadir;
}
if (!xadir->d_inode) {
int err;
if (flags == 0 || flags & XATTR_CREATE) {
/* Although there is nothing else trying to create this directory,
* another directory with the same hash may be created, so we need
* to protect against that */
err = xaroot->d_inode->i_op->mkdir (xaroot->d_inode, xadir, 0700);
if (err) {
dput (xaroot);
dput (xadir);
return ERR_PTR (err);
}
}
if (!xadir->d_inode) {
dput (xaroot);
dput (xadir);
return ERR_PTR (-ENODATA);
}
/* Newly created object.. Need to mark it private */
REISERFS_I(xadir->d_inode)->i_flags |= i_priv_object;
}
dput (xaroot);
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_PTR (PTR_ERR (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_PTR (PTR_ERR (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_sem 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;
}
/* Newly created object.. Need to mark it private */
REISERFS_I(xafile->d_inode)->i_flags |= i_priv_object;
}
out:
dput (xadir);
if (err)
xafile = ERR_PTR (err);
return xafile;
}
/* Opens a file pointer to the attribute associated with inode */
static struct file *
open_xa_file (const struct inode *inode, const char *name, int flags)
{
struct dentry *xafile;
struct file *fp;
xafile = get_xa_file_dentry (inode, name, flags);
if (IS_ERR (xafile))
return ERR_PTR (PTR_ERR (xafile));
else if (!xafile->d_inode) {
dput (xafile);
return ERR_PTR (-ENODATA);
}
fp = dentry_open (xafile, NULL, O_RDWR);
/* dentry_open dputs the dentry if it fails */
return fp;
}
/*
* this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
* we need to drop the path before calling the filldir struct. That
* would be a big performance hit to the non-xattr case, so I've copied
* the whole thing for now. --clm
*
* the big difference is that I go backwards through the directory,
* and don't mess with f->f_pos, but the idea is the same. Do some
* action on each and every entry in the directory.
*
* we're called with i_sem held, so there are no worries about the directory
* changing underneath us.
*/
static int __xattr_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH (path_to_entry);
struct buffer_head * bh;
int entry_num;
struct item_head * ih, tmp_ih;
int search_res;
char * local_buf;
loff_t next_pos;
char small_buf[32] ; /* avoid kmalloc if we can */
struct reiserfs_de_head *deh;
int d_reclen;
char * d_name;
off_t d_off;
ino_t d_ino;
struct reiserfs_dir_entry de;
/* form key for search the next directory entry using f_pos field of
file structure */
next_pos = max_reiserfs_offset(inode);
while (1) {
research:
if (next_pos <= DOT_DOT_OFFSET)
break;
make_cpu_key (&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);
search_res = search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, &de);
if (search_res == IO_ERROR) {
// FIXME: we could just skip part of directory which could
// not be read
pathrelse(&path_to_entry);
return -EIO;
}
if (search_res == NAME_NOT_FOUND)
de.de_entry_num--;
set_de_name_and_namelen(&de);
entry_num = de.de_entry_num;
deh = &(de.de_deh[entry_num]);
bh = de.de_bh;
ih = de.de_ih;
if (!is_direntry_le_ih(ih)) {
reiserfs_warning("not direntry %h\n", ih);
break;
}
copy_item_head(&tmp_ih, ih);
/* we must have found item, that is item of this directory, */
RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
"vs-9000: found item %h does not match to dir we readdir %K",
ih, &pos_key);
if (deh_offset(deh) <= DOT_DOT_OFFSET) {
break;
}
/* look for the previous entry in the directory */
next_pos = deh_offset (deh) - 1;
if (!de_visible (deh))
/* it is hidden entry */
continue;
d_reclen = entry_length(bh, ih, entry_num);
d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh);
d_off = deh_offset (deh);
d_ino = deh_objectid (deh);
if (!d_name[d_reclen - 1])
d_reclen = strlen (d_name);
if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
/* too big to send back to VFS */
continue ;
}
/* Ignore the .reiserfs_priv entry */
if (reiserfs_xattrs (inode->i_sb) &&
!old_format_only(inode->i_sb) &&
deh_objectid (deh) == le32_to_cpu (INODE_PKEY(REISERFS_SB(inode->i_sb)->priv_root->d_inode)->k_objectid))
continue;
if (d_reclen <= 32) {
local_buf = small_buf ;
} else {
local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
if (!local_buf) {
pathrelse (&path_to_entry);
return -ENOMEM ;
}
if (item_moved (&tmp_ih, &path_to_entry)) {
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
/* sigh, must retry. Do this same offset again */
next_pos = d_off;
goto research;
}
}
// Note, that we copy name to user space via temporary
// buffer (local_buf) because filldir will block if
// user space buffer is swapped out. At that time
// entry can move to somewhere else
memcpy (local_buf, d_name, d_reclen);
/* the filldir function might need to start transactions,
* or do who knows what. Release the path now that we've
* copied all the important stuff out of the deh
*/
pathrelse (&path_to_entry);
if (filldir (dirent, local_buf, d_reclen, d_off, d_ino,
DT_UNKNOWN) < 0) {
if (local_buf != small_buf) {
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
}
goto end;
}
if (local_buf != small_buf) {
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
}
} /* while */
end:
pathrelse (&path_to_entry);
return 0;
}
/*
* this could be done with dedicated readdir ops for the xattr files,
* but I want to get something working asap
* this is stolen from vfs_readdir
*
*/
static
int xattr_readdir(struct file *file, filldir_t filler, void *buf)
{
struct inode *inode = file->f_dentry->d_inode;
int res = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
down(&inode->i_sem);
// down(&inode->i_zombie);
res = -ENOENT;
if (!IS_DEADDIR(inode)) {
lock_kernel();
res = __xattr_readdir(file, buf, filler);
unlock_kernel();
}
// up(&inode->i_zombie);
up(&inode->i_sem);
out:
return res;
}
/* Internal operations on file data */
static inline void
reiserfs_put_page(struct page *page)
{
kunmap(page);
page_cache_release(page);
}
static struct page *
reiserfs_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
struct page *page;
/* We can deadlock if we try to free dentries,
and an unlink/rmdir has just occured - GFP_NOFS avoids this */
mapping->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS;
page = read_cache_page (mapping, n,
(filler_t*)mapping->a_ops->readpage, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
if (!PageUptodate(page))
goto fail;
if (PageError(page))
goto fail;
}
return page;
fail:
reiserfs_put_page(page);
return ERR_PTR(-EIO);
}
static inline __u32
xattr_hash (const char *msg, int len)
{
return csum_partial (msg, len, 0);
}
/* Generic extended attribute operations that can be used by xa plugins */
/*
* inode->i_sem: down
*/
int
reiserfs_xattr_set (struct inode *inode, const char *name, const void *buffer,
size_t buffer_size, int flags)
{
int err = 0;
struct file *fp;
struct page *page;
char *data;
struct address_space *mapping;
size_t file_pos = 0;
size_t buffer_pos = 0;
struct inode *xinode;
struct iattr newattrs;
__u32 xahash = 0;
if (IS_RDONLY (inode))
return -EROFS;
if (IS_IMMUTABLE (inode) || IS_APPEND (inode))
return -EPERM;
if (get_inode_sd_version (inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
/* Empty xattrs are ok, they're just empty files, no hash */
if (buffer && buffer_size)
xahash = xattr_hash (buffer, buffer_size);
open_file:
fp = open_xa_file (inode, name, flags);
if (IS_ERR (fp)) {
err = PTR_ERR (fp);
goto out;
}
xinode = fp->f_dentry->d_inode;
/* we need to copy it off.. */
if (xinode->i_nlink > 1) {
fput(fp);
err = reiserfs_xattr_del (inode, name);
if (err < 0)
goto out;
/* We just killed the old one, we're not replacing anymore */
if (flags & XATTR_REPLACE)
flags &= ~XATTR_REPLACE;
goto open_file;
}
/* Resize it so we're ok to write there */
newattrs.ia_size = buffer_size;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
down (&xinode->i_sem);
err = notify_change(fp->f_dentry, &newattrs);
if (err)
goto out_filp;
mapping = xinode->i_mapping;
while (buffer_pos < buffer_size || buffer_pos == 0) {
size_t chunk;
size_t skip = 0;
size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));
if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)
chunk = PAGE_CACHE_SIZE;
else
chunk = buffer_size - buffer_pos;
page = reiserfs_get_page (xinode, file_pos >> PAGE_CACHE_SHIFT);
if (IS_ERR (page)) {
err = PTR_ERR (page);
goto out_filp;
}
lock_page (page);
data = page_address (page);
if (file_pos == 0) {
struct reiserfs_xattr_header *rxh;
skip = file_pos = sizeof (struct reiserfs_xattr_header);
if (chunk + skip > PAGE_CACHE_SIZE)
chunk = PAGE_CACHE_SIZE - skip;
rxh = (struct reiserfs_xattr_header *)data;
rxh->h_magic = cpu_to_le32 (REISERFS_XATTR_MAGIC);
rxh->h_hash = cpu_to_le32 (xahash);
}
err = mapping->a_ops->prepare_write (fp, page, page_offset,
page_offset + chunk + skip);
if (!err) {
if (buffer)
memcpy (data + skip, buffer + buffer_pos, chunk);
err = mapping->a_ops->commit_write (fp, page, page_offset,
page_offset + chunk + skip);
}
unlock_page (page);
reiserfs_put_page (page);
buffer_pos += chunk;
file_pos += chunk;
skip = 0;
if (err || buffer_size == 0 || !buffer)
break;
}
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty (inode);
out_filp:
up (&xinode->i_sem);
fput(fp);
out:
return err;
}
/*
* inode->i_sem: down
*/
int
reiserfs_xattr_get (const struct inode *inode, const char *name, void *buffer,
size_t buffer_size)
{
ssize_t err = 0;
struct file *fp;
size_t isize;
size_t file_pos = 0;
size_t buffer_pos = 0;
struct page *page;
struct inode *xinode;
__u32 hash = 0;
if (name == NULL)
return -EINVAL;
/* We can't have xattrs attached to v1 items since they don't have
* generation numbers */
if (get_inode_sd_version (inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
fp = open_xa_file (inode, name, FL_READONLY);
if (IS_ERR (fp)) {
err = PTR_ERR (fp);
goto out;
}
xinode = fp->f_dentry->d_inode;
isize = xinode->i_size;
/* Just return the size needed */
if (buffer == NULL) {
err = isize - sizeof (struct reiserfs_xattr_header);
goto out_dput;
}
if (buffer_size < isize - sizeof (struct reiserfs_xattr_header)) {
err = -ERANGE;
goto out_dput;
}
while (file_pos < isize) {
size_t chunk;
char *data;
size_t skip = 0;
if (isize - file_pos > PAGE_CACHE_SIZE)
chunk = PAGE_CACHE_SIZE;
else
chunk = isize - file_pos;
page = reiserfs_get_page (xinode, file_pos >> PAGE_CACHE_SHIFT);
if (IS_ERR (page)) {
err = PTR_ERR (page);
goto out_dput;
}
lock_page (page);
data = page_address (page);
if (file_pos == 0) {
struct reiserfs_xattr_header *rxh =
(struct reiserfs_xattr_header *)data;
skip = file_pos = sizeof (struct reiserfs_xattr_header);
chunk -= skip;
/* Magic doesn't match up.. */
if (rxh->h_magic != cpu_to_le32 (REISERFS_XATTR_MAGIC)) {
unlock_page (page);
reiserfs_put_page (page);
reiserfs_warning ("reiserfs: Invalid magic for xattr (%s) "
"associated with %s %k\n", name,
reiserfs_bdevname (inode->i_sb),
INODE_PKEY (inode));
err = -EIO;
goto out_dput;
}
hash = le32_to_cpu (rxh->h_hash);
}
memcpy (buffer + buffer_pos, data + skip, chunk);
unlock_page (page);
reiserfs_put_page (page);
file_pos += chunk;
buffer_pos += chunk;
skip = 0;
}
err = isize - sizeof (struct reiserfs_xattr_header);
if (xattr_hash (buffer, isize - sizeof (struct reiserfs_xattr_header)) != hash) {
reiserfs_warning ("reiserfs: Invalid hash for xattr (%s) associated "
"with %s %k\n", name,
reiserfs_bdevname (inode->i_sb), INODE_PKEY (inode));
err = -EIO;
}
out_dput:
fput(fp);
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_reiserfs_priv_object (dentry->d_inode)) {
reiserfs_warning ("OID %08x [%.*s/%.*s] doesn't have priv flag set [parent is %sset].\n",
le32_to_cpu (INODE_PKEY (dentry->d_inode)->k_objectid),
xadir->d_name.len, xadir->d_name.name, namelen, name,
is_reiserfs_priv_object (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;
}
int
reiserfs_xattr_del (struct inode *inode, const char *name)
{
struct dentry *dir;
int err;
if (IS_RDONLY (inode))
return -EROFS;
dir = open_xa_dir (inode, FL_READONLY);
if (IS_ERR (dir)) {
err = PTR_ERR (dir);
goto out;
}
err = __reiserfs_xattr_del (dir, name, strlen (name));
dput (dir);
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, ino_t ino, unsigned int d_type)
{
struct dentry *xadir = (struct dentry *)buf;
return __reiserfs_xattr_del (xadir, name, namelen);
}
/* This is called w/ inode->i_sem downed */
int
reiserfs_delete_xattrs (struct inode *inode)
{
struct file *fp;
struct dentry *dir, *root;
int err = 0;
/* Skip out, an xattr has no xattrs associated with it */
if (is_reiserfs_priv_object (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;
}
fp = dentry_open (dir, NULL, O_RDWR);
if (IS_ERR (fp)) {
err = PTR_ERR (fp);
/* dentry_open dputs the dentry if it fails */
goto out;
}
lock_kernel ();
err = xattr_readdir (fp, 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);
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 ("Couldn't remove all entries in directory\n");
}
unlock_kernel ();
out_dir:
fput(fp);
out:
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, ino_t 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 file *fp;
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_reiserfs_priv_object (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;
}
fp = dentry_open (dir, NULL, O_RDWR);
if (IS_ERR (fp)) {
err = PTR_ERR (fp);
/* dentry_open dputs the dentry if it fails */
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 (fp, reiserfs_chown_xattrs_filler, &buf);
if (err) {
unlock_kernel ();
goto out_dir;
}
err = notify_change (dir, attrs);
unlock_kernel ();
out_dir:
fput(fp);
out:
attrs->ia_valid = ia_valid;
return err;
}
/* Actual operations that are exported to VFS-land */
/*
* Inode operation getxattr()
* Preliminary locking: we down dentry->d_inode->i_sem
*/
ssize_t
reiserfs_getxattr (struct dentry *dentry, const char *name, void *buffer,
size_t size)
{
struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
int err;
if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
down (&dentry->d_inode->i_sem);
reiserfs_read_lock_xattrs (dentry->d_sb);
err = xah->get (dentry->d_inode, name, buffer, size);
reiserfs_read_unlock_xattrs (dentry->d_sb);
up (&dentry->d_inode->i_sem);
return err;
}
/*
* Inode operation setxattr()
*
* dentry->d_inode->i_sem down
*/
int
reiserfs_setxattr (struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
int err;
if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
if (IS_RDONLY (dentry->d_inode))
return -EROFS;
if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
return -EROFS;
reiserfs_write_lock_xattrs (dentry->d_sb);
err = xah->set (dentry->d_inode, name, value, size, flags);
reiserfs_write_unlock_xattrs (dentry->d_sb);
return err;
}
/*
* Inode operation removexattr()
*
* dentry->d_inode->i_sem down
*/
int
reiserfs_removexattr (struct dentry *dentry, const char *name)
{
int err;
struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
if (IS_RDONLY (dentry->d_inode))
return -EROFS;
if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
return -EPERM;
reiserfs_read_lock_xattrs (dentry->d_sb);
/* Deletion pre-operation */
if (xah->del) {
err = xah->del (dentry->d_inode, name);
if (err)
goto out;
}
err = reiserfs_xattr_del (dentry->d_inode, name);
dentry->d_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty (dentry->d_inode);
out:
reiserfs_read_unlock_xattrs (dentry->d_sb);
return err;
}
/* This is what filldir will use:
* r_pos will always contain the amount of space required for the entire
* list. If r_pos becomes larger than r_size, we need more space and we
* return an error indicating this. If r_pos is less than r_size, then we've
* filled the buffer successfully and we return success */
struct reiserfs_listxattr_buf {
int r_pos;
int r_size;
char *r_buf;
struct inode *r_inode;
};
static int
reiserfs_listxattr_filler (void *buf, const char *name, int namelen,
loff_t offset, ino_t ino, unsigned int d_type)
{
struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
int len = 0;
if (name[0] != '.' || (namelen != 1 && (name[1] != '.' || namelen != 2))) {
struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
if (!xah) return 0; /* Unsupported xattr name, skip it */
/* We call ->list() twice because the operation isn't required to just
* return the name back - we want to make sure we have enough space */
len += xah->list (b->r_inode, name, namelen, NULL);
if (len) {
if (b->r_pos + len + 1 <= b->r_size) {
char *p = b->r_buf + b->r_pos;
p += xah->list (b->r_inode, name, namelen, p);
*p++ = '\0';
}
b->r_pos += len + 1;
}
}
return 0;
}
/*
* Inode operation listxattr()
*
* Preliminary locking: we down dentry->d_inode->i_sem
*/
ssize_t
reiserfs_listxattr (struct dentry *dentry, char *buffer, size_t size)
{
struct file *fp;
struct dentry *dir;
int err = 0;
struct reiserfs_listxattr_buf buf;
if (!dentry->d_inode)
return -EINVAL;
if (!reiserfs_xattrs(dentry->d_sb) ||
get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
down (&dentry->d_inode->i_sem);
reiserfs_read_lock_xattrs (dentry->d_sb);
dir = open_xa_dir (dentry->d_inode, FL_READONLY);
reiserfs_read_unlock_xattrs (dentry->d_sb);
if (IS_ERR (dir)) {
err = PTR_ERR (dir);
if (err == -ENODATA)
err = 0; /* Not an error if there aren't any xattrs */
goto out;
}
fp = dentry_open (dir, NULL, O_RDWR);
if (IS_ERR (fp)) {
err = PTR_ERR (fp);
/* dentry_open dputs the dentry if it fails */
goto out;
}
buf.r_buf = buffer;
buf.r_size = buffer ? size : 0;
buf.r_pos = 0;
buf.r_inode = dentry->d_inode;
err = xattr_readdir (fp, reiserfs_listxattr_filler, &buf);
if (err)
goto out_dir;
if (buf.r_pos > buf.r_size && buffer != NULL)
err = -ERANGE;
else
err = buf.r_pos;
out_dir:
fput(fp);
out:
up (&dentry->d_inode->i_sem);
return err;
}
/* This is the implementation for the xattr plugin infrastructure */
static struct list_head xattr_handlers = LIST_HEAD_INIT (xattr_handlers);
static rwlock_t handler_lock = RW_LOCK_UNLOCKED;
static struct reiserfs_xattr_handler *
find_xattr_handler_prefix (const char *prefix)
{
struct reiserfs_xattr_handler *xah = NULL;
struct list_head *p;
read_lock (&handler_lock);
list_for_each (p, &xattr_handlers) {
xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
if (strncmp (xah->prefix, prefix, strlen (xah->prefix)) == 0)
break;
xah = NULL;
}
read_unlock (&handler_lock);
return xah;
}
static void
__unregister_handlers (void)
{
struct reiserfs_xattr_handler *xah;
struct list_head *p, *tmp;
list_for_each_safe (p, tmp, &xattr_handlers) {
xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
if (xah->exit)
xah->exit();
list_del_init (p);
}
INIT_LIST_HEAD (&xattr_handlers);
}
int __init
reiserfs_xattr_register_handlers (void)
{
int err = 0;
struct reiserfs_xattr_handler *xah;
struct list_head *p;
write_lock (&handler_lock);
/* If we're already initialized, nothing to do */
if (!list_empty (&xattr_handlers)) {
write_unlock (&handler_lock);
return 0;
}
/* Add the handlers */
list_add_tail (&user_handler.handlers, &xattr_handlers);
/* Run initializers, if available */
list_for_each (p, &xattr_handlers) {
xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
if (xah->init) {
err = xah->init ();
if (err) {
list_del_init (p);
break;
}
}
}
/* Clean up other handlers, if any failed */
if (err)
__unregister_handlers ();
write_unlock (&handler_lock);
return err;
}
void
reiserfs_xattr_unregister_handlers (void)
{
write_lock (&handler_lock);
__unregister_handlers ();
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;
}
return 0;
}
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 ("reiserfs: xattrs not supported on pre v3.6 "
"format filesystem. Failing mount.\n");
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;
down (&inode->i_sem);
err = inode->i_op->mkdir (inode, dentry, 0700);
up (&inode->i_sem);
if (err) {
dput (dentry);
dentry = NULL;
}
if (dentry && dentry->d_inode)
reiserfs_warning ("reiserfs: Created %s on %s - reserved for "
"xattr storage.\n", PRIVROOT_NAME,
reiserfs_bdevname (inode->i_sb));
} 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;
REISERFS_I(dentry->d_inode)->i_flags |= i_priv_object;
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 ("reiserfs: xattrs enabled and couldn't "
"find/create .reiserfs_priv. Failing mount.\n");
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));
}
return err;
}
int
reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd)
{
umode_t mode = inode->i_mode;
if (mask & MAY_WRITE) {
/*
* Nobody gets write access to a read-only fs.
*/
if (IS_RDONLY(inode) &&
(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
return -EROFS;
/*
* Nobody gets write access to an immutable file.
*/
if (IS_IMMUTABLE(inode))
return -EACCES;
}
/* We don't do permission checks on the internal objects.
* Permissions are determined by the "owning" object. */
if (is_reiserfs_priv_object (inode))
return 0;
if (current->fsuid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
/*
* If the DACs are ok we don't need any capability check.
*/
if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))
return 0;
/*
* Read/write DACs are always overridable.
* Executable DACs are overridable if at least one exec bit is set.
*/
if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO))
if (capable(CAP_DAC_OVERRIDE))
return 0;
/*
* Searching includes executable on directories, else just read.
*/
if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
if (capable(CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
}
#include <linux/reiserfs_fs.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <asm/uaccess.h>
#define XATTR_USER_PREFIX "user."
static int
user_get (struct inode *inode, const char *name, void *buffer, size_t size)
{
int error;
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
if (!reiserfs_xattrs_user (inode->i_sb))
return -EOPNOTSUPP;
error = permission (inode, MAY_READ, NULL);
if (error)
return error;
return reiserfs_xattr_get (inode, name, buffer, size);
}
static int
user_set (struct inode *inode, const char *name, const void *buffer,
size_t size, int flags)
{
int error;
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
if (!reiserfs_xattrs_user (inode->i_sb))
return -EOPNOTSUPP;
if (!S_ISREG (inode->i_mode) &&
(!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
return -EPERM;
error = permission (inode, MAY_WRITE, NULL);
if (error)
return error;
return reiserfs_xattr_set (inode, name, buffer, size, flags);
}
static int
user_del (struct inode *inode, const char *name)
{
int error;
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
if (!reiserfs_xattrs_user (inode->i_sb))
return -EOPNOTSUPP;
if (!S_ISREG (inode->i_mode) &&
(!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
return -EPERM;
error = permission (inode, MAY_WRITE, NULL);
if (error)
return error;
return 0;
}
static int
user_list (struct inode *inode, const char *name, int namelen, char *out)
{
int len = namelen;
if (!reiserfs_xattrs_user (inode->i_sb))
return 0;
if (out)
memcpy (out, name, len);
return len;
}
struct reiserfs_xattr_handler user_handler = {
prefix: XATTR_USER_PREFIX,
get: user_get,
set: user_set,
del: user_del,
list: user_list,
};
...@@ -287,7 +287,7 @@ struct unfm_nodeinfo { ...@@ -287,7 +287,7 @@ struct unfm_nodeinfo {
#define STAT_DATA_V2 1 #define STAT_DATA_V2 1
static inline struct reiserfs_inode_info *REISERFS_I(struct inode *inode) static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
{ {
return container_of(inode, struct reiserfs_inode_info, vfs_inode); return container_of(inode, struct reiserfs_inode_info, vfs_inode);
} }
...@@ -1960,6 +1960,7 @@ void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * ...@@ -1960,6 +1960,7 @@ void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode *
void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode ); void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode );
void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ); void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs );
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
/* namei.c */ /* namei.c */
void set_de_name_and_namelen (struct reiserfs_dir_entry * de); void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
...@@ -2010,6 +2011,8 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset, ...@@ -2010,6 +2011,8 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
/* dir.c */ /* dir.c */
extern struct inode_operations reiserfs_dir_inode_operations; extern struct inode_operations reiserfs_dir_inode_operations;
extern struct inode_operations reiserfs_symlink_inode_operations;
extern struct inode_operations reiserfs_special_inode_operations;
extern struct file_operations reiserfs_dir_operations; extern struct file_operations reiserfs_dir_operations;
/* tail_conversion.c */ /* tail_conversion.c */
...@@ -2237,6 +2240,9 @@ int reiserfs_unpack (struct inode * inode, struct file * filp); ...@@ -2237,6 +2240,9 @@ int reiserfs_unpack (struct inode * inode, struct file * filp);
#define reiserfs_write_lock( sb ) lock_kernel() #define reiserfs_write_lock( sb ) lock_kernel()
#define reiserfs_write_unlock( sb ) unlock_kernel() #define reiserfs_write_unlock( sb ) unlock_kernel()
/* xattr stuff */
#define REISERFS_XATTR_DIR_SEM(s) (REISERFS_SB(s)->xattr_dir_sem)
#endif /* _LINUX_REISER_FS_H */ #endif /* _LINUX_REISER_FS_H */
...@@ -22,7 +22,8 @@ typedef enum { ...@@ -22,7 +22,8 @@ typedef enum {
truncate or unlink. Safe link is used to avoid leakage of disk truncate or unlink. Safe link is used to avoid leakage of disk
space on crash with some files open, but unlinked. */ space on crash with some files open, but unlinked. */
i_link_saved_unlink_mask = 0x0010, i_link_saved_unlink_mask = 0x0010,
i_link_saved_truncate_mask = 0x0020 i_link_saved_truncate_mask = 0x0020,
i_priv_object = 0x0080,
} reiserfs_inode_flags; } reiserfs_inode_flags;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/rwsem.h>
#endif #endif
typedef enum { typedef enum {
...@@ -251,7 +252,6 @@ struct reiserfs_journal { ...@@ -251,7 +252,6 @@ struct reiserfs_journal {
#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */
typedef __u32 (*hashf_t) (const signed char *, int); typedef __u32 (*hashf_t) (const signed char *, int);
struct reiserfs_bitmap_info struct reiserfs_bitmap_info
...@@ -395,6 +395,10 @@ struct reiserfs_sb_info ...@@ -395,6 +395,10 @@ struct reiserfs_sb_info
struct proc_dir_entry *procdir; struct proc_dir_entry *procdir;
int reserved_blocks; /* amount of blocks reserved for further allocations */ 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 */ spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
struct dentry *priv_root; /* root of /.reiserfs_priv */
struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
struct rw_semaphore xattr_dir_sem;
}; };
/* Definitions of reiserfs on-disk properties: */ /* Definitions of reiserfs on-disk properties: */
...@@ -437,6 +441,8 @@ enum reiserfs_mount_options { ...@@ -437,6 +441,8 @@ enum reiserfs_mount_options {
REISERFS_NO_UNHASHED_RELOCATION, REISERFS_NO_UNHASHED_RELOCATION,
REISERFS_HASHED_RELOCATION, REISERFS_HASHED_RELOCATION,
REISERFS_ATTRS, REISERFS_ATTRS,
REISERFS_XATTRS,
REISERFS_XATTRS_USER,
REISERFS_TEST1, REISERFS_TEST1,
REISERFS_TEST2, REISERFS_TEST2,
...@@ -462,6 +468,9 @@ enum reiserfs_mount_options { ...@@ -462,6 +468,9 @@ enum reiserfs_mount_options {
#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG)) #define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED)) #define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK)) #define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
#define reiserfs_xattrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS))
#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
#define reiserfs_xattrs_optional(s) reiserfs_xattrs_user(s)
void reiserfs_file_buffer (struct buffer_head * bh, int list); void reiserfs_file_buffer (struct buffer_head * bh, int list);
extern struct file_system_type reiserfs_fs_type; extern struct file_system_type reiserfs_fs_type;
......
/*
File: linux/reiserfs_xattr.h
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/xattr.h>
/* Magic value in header */
#define REISERFS_XATTR_MAGIC 0x52465841 /* "RFXA" */
struct reiserfs_xattr_header {
__u32 h_magic; /* magic number for identification */
__u32 h_hash; /* hash of the value */
};
#ifdef __KERNEL__
struct reiserfs_xattr_handler {
char *prefix;
int (*init)(void);
void (*exit)(void);
int (*get)(struct inode *inode, const char *name, void *buffer,
size_t size);
int (*set)(struct inode *inode, const char *name, const void *buffer,
size_t size, int flags);
int (*del)(struct inode *inode, const char *name);
int (*list)(struct inode *inode, const char *name, int namelen, char *out);
struct list_head handlers;
};
#ifdef CONFIG_REISERFS_FS_XATTR
#define is_reiserfs_priv_object(inode) (REISERFS_I(inode)->i_flags & i_priv_object)
ssize_t reiserfs_getxattr (struct dentry *dentry, const char *name,
void *buffer, size_t size);
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, struct nameidata *nd);
int reiserfs_xattr_del (struct inode *, const char *);
int reiserfs_xattr_get (const struct inode *, const char *, void *, size_t);
int reiserfs_xattr_set (struct inode *, const char *, const void *,
size_t, int);
extern struct reiserfs_xattr_handler user_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));
}
static inline void
reiserfs_write_unlock_xattrs(struct super_block *sb)
{
up_write (&REISERFS_XATTR_DIR_SEM(sb));
}
static inline void
reiserfs_read_lock_xattrs(struct super_block *sb)
{
down_read (&REISERFS_XATTR_DIR_SEM(sb));
}
static inline void
reiserfs_read_unlock_xattrs(struct super_block *sb)
{
up_read (&REISERFS_XATTR_DIR_SEM(sb));
}
#else
#define is_reiserfs_priv_object(inode) 0
#define reiserfs_getxattr NULL
#define reiserfs_setxattr NULL
#define reiserfs_listxattr NULL
#define reiserfs_removexattr NULL
#define reiserfs_write_lock_xattrs(sb)
#define reiserfs_write_unlock_xattrs(sb)
#define reiserfs_read_lock_xattrs(sb)
#define reiserfs_read_unlock_xattrs(sb)
#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) { return 0; };
#endif
#endif /* __KERNEL__ */
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