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>
...@@ -358,6 +359,16 @@ static void reiserfs_put_super (struct super_block * s) ...@@ -358,6 +359,16 @@ 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) {
...@@ -1450,12 +1471,24 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) ...@@ -1450,12 +1471,24 @@ 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);
......
This diff is collapsed.
#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