Commit f7cfad91 authored by Theodore Y. Ts'o's avatar Theodore Y. Ts'o Committed by Linus Torvalds

Port of (bugfixed) 0.8.50 xattr-ext3 to 2.5 (w/ hch cleanups. mbcache API)

This patch adds extended attribute support to the ext3 filesystem.  This
uses the generic extended attribute patch which was developed by Andreas
Gruenbacher and the XFS team.  As a result, the user space utilities
which work for XFS will also work with these patches.
parent 7cbc2add
...@@ -289,6 +289,17 @@ config EXT3_FS ...@@ -289,6 +289,17 @@ config EXT3_FS
of your root partition (the one containing the directory /) cannot of your root partition (the one containing the directory /) cannot
be compiled as a module, and so this may be dangerous. be compiled as a module, and so this may be dangerous.
config EXT3_FS_XATTR
bool "Ext3 extended attributes"
depends on EXT3_FS
default y
---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_JBD could be its own option (even modular), but until there are # CONFIG_JBD could be its own option (even modular), but until there are
# other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS
# dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS # dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
......
...@@ -7,4 +7,10 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ...@@ -7,4 +7,10 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
ext3-objs := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ext3-objs := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
ioctl.o namei.o super.o symlink.o hash.o ioctl.o namei.o super.o symlink.o hash.o
export-objs += xattr.o
ifeq ($(CONFIG_EXT3_FS_XATTR),y)
ext3-objs += xattr.o xattr_user.o
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/jbd.h> #include <linux/jbd.h>
#include <linux/ext3_fs.h> #include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h> #include <linux/ext3_jbd.h>
#include <linux/smp_lock.h> #include "xattr.h"
/* /*
* Called when an inode is released. Note that this is different * Called when an inode is released. Note that this is different
...@@ -98,5 +98,9 @@ struct file_operations ext3_file_operations = { ...@@ -98,5 +98,9 @@ struct file_operations ext3_file_operations = {
struct inode_operations ext3_file_inode_operations = { struct inode_operations ext3_file_inode_operations = {
.truncate = ext3_truncate, .truncate = ext3_truncate,
.setattr = ext3_setattr, .setattr = ext3_setattr,
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
}; };
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "xattr.h"
/* /*
* ialloc.c contains the inodes allocation and deallocation routines * ialloc.c contains the inodes allocation and deallocation routines
*/ */
...@@ -118,6 +120,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) ...@@ -118,6 +120,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode)
* as writing the quota to disk may need the lock as well. * as writing the quota to disk may need the lock as well.
*/ */
DQUOT_INIT(inode); DQUOT_INIT(inode);
ext3_xattr_delete_inode(handle, inode);
DQUOT_FREE_INODE(inode); DQUOT_FREE_INODE(inode);
DQUOT_DROP(inode); DQUOT_DROP(inode);
......
...@@ -42,6 +42,18 @@ ...@@ -42,6 +42,18 @@
*/ */
#undef SEARCH_FROM_ZERO #undef SEARCH_FROM_ZERO
/*
* Test whether an inode is a fast symlink.
*/
static inline int ext3_inode_is_fast_symlink(struct inode *inode)
{
int ea_blocks = EXT3_I(inode)->i_file_acl ?
(inode->i_sb->s_blocksize >> 9) : 0;
return (S_ISLNK(inode->i_mode) &&
inode->i_blocks - ea_blocks == 0);
}
/* The ext3 forget function must perform a revoke if we are freeing data /* The ext3 forget function must perform a revoke if we are freeing data
* which has been journaled. Metadata (eg. indirect blocks) must be * which has been journaled. Metadata (eg. indirect blocks) must be
* revoked in all cases. * revoked in all cases.
...@@ -51,7 +63,7 @@ ...@@ -51,7 +63,7 @@
* still needs to be revoked. * still needs to be revoked.
*/ */
static int ext3_forget(handle_t *handle, int is_metadata, int ext3_forget(handle_t *handle, int is_metadata,
struct inode *inode, struct buffer_head *bh, struct inode *inode, struct buffer_head *bh,
int blocknr) int blocknr)
{ {
...@@ -167,9 +179,7 @@ void ext3_delete_inode (struct inode * inode) ...@@ -167,9 +179,7 @@ void ext3_delete_inode (struct inode * inode)
{ {
handle_t *handle; handle_t *handle;
if (is_bad_inode(inode) || if (is_bad_inode(inode))
inode->i_ino == EXT3_ACL_IDX_INO ||
inode->i_ino == EXT3_ACL_DATA_INO)
goto no_delete; goto no_delete;
lock_kernel(); lock_kernel();
...@@ -1979,6 +1989,8 @@ void ext3_truncate(struct inode * inode) ...@@ -1979,6 +1989,8 @@ void ext3_truncate(struct inode * inode)
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return; return;
if (ext3_inode_is_fast_symlink(inode))
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return; return;
...@@ -2130,8 +2142,6 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) ...@@ -2130,8 +2142,6 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc)
struct ext3_group_desc * gdp; struct ext3_group_desc * gdp;
if ((inode->i_ino != EXT3_ROOT_INO && if ((inode->i_ino != EXT3_ROOT_INO &&
inode->i_ino != EXT3_ACL_IDX_INO &&
inode->i_ino != EXT3_ACL_DATA_INO &&
inode->i_ino != EXT3_JOURNAL_INO && inode->i_ino != EXT3_JOURNAL_INO &&
inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
inode->i_ino > le32_to_cpu( inode->i_ino > le32_to_cpu(
...@@ -2263,10 +2273,7 @@ void ext3_read_inode(struct inode * inode) ...@@ -2263,10 +2273,7 @@ void ext3_read_inode(struct inode * inode)
brelse (iloc.bh); brelse (iloc.bh);
if (inode->i_ino == EXT3_ACL_IDX_INO || if (S_ISREG(inode->i_mode)) {
inode->i_ino == EXT3_ACL_DATA_INO)
/* Nothing to do */ ;
else if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext3_file_inode_operations; inode->i_op = &ext3_file_inode_operations;
inode->i_fop = &ext3_file_operations; inode->i_fop = &ext3_file_operations;
if (ext3_should_writeback_data(inode)) if (ext3_should_writeback_data(inode))
...@@ -2277,18 +2284,20 @@ void ext3_read_inode(struct inode * inode) ...@@ -2277,18 +2284,20 @@ void ext3_read_inode(struct inode * inode)
inode->i_op = &ext3_dir_inode_operations; inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations; inode->i_fop = &ext3_dir_operations;
} else if (S_ISLNK(inode->i_mode)) { } else if (S_ISLNK(inode->i_mode)) {
if (!inode->i_blocks) if (ext3_inode_is_fast_symlink(inode))
inode->i_op = &ext3_fast_symlink_inode_operations; inode->i_op = &ext3_fast_symlink_inode_operations;
else { else {
inode->i_op = &page_symlink_inode_operations; inode->i_op = &ext3_symlink_inode_operations;
if (ext3_should_writeback_data(inode)) if (ext3_should_writeback_data(inode))
inode->i_mapping->a_ops = &ext3_writeback_aops; inode->i_mapping->a_ops = &ext3_writeback_aops;
else else
inode->i_mapping->a_ops = &ext3_aops; inode->i_mapping->a_ops = &ext3_aops;
} }
} else } else {
inode->i_op = &ext3_special_inode_operations;
init_special_inode(inode, inode->i_mode, init_special_inode(inode, inode->i_mode,
le32_to_cpu(iloc.raw_inode->i_block[0])); le32_to_cpu(iloc.raw_inode->i_block[0]));
}
if (ei->i_flags & EXT3_SYNC_FL) if (ei->i_flags & EXT3_SYNC_FL)
inode->i_flags |= S_SYNC; inode->i_flags |= S_SYNC;
if (ei->i_flags & EXT3_APPEND_FL) if (ei->i_flags & EXT3_APPEND_FL)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include "xattr.h"
/* /*
...@@ -1654,7 +1655,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) ...@@ -1654,7 +1655,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, S_IFDIR); inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
err = PTR_ERR(inode); err = PTR_ERR(inode);
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_stop; goto out_stop;
...@@ -1662,7 +1663,6 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) ...@@ -1662,7 +1663,6 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &ext3_dir_inode_operations; inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations; inode->i_fop = &ext3_dir_operations;
inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
inode->i_blocks = 0;
dir_block = ext3_bread (handle, inode, 0, 1, &err); dir_block = ext3_bread (handle, inode, 0, 1, &err);
if (!dir_block) { if (!dir_block) {
inode->i_nlink--; /* is this nlink == 0? */ inode->i_nlink--; /* is this nlink == 0? */
...@@ -1689,9 +1689,6 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) ...@@ -1689,9 +1689,6 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
ext3_journal_dirty_metadata(handle, dir_block); ext3_journal_dirty_metadata(handle, dir_block);
brelse (dir_block); brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
ext3_mark_inode_dirty(handle, inode); ext3_mark_inode_dirty(handle, inode);
err = ext3_add_entry (handle, dentry, inode); err = ext3_add_entry (handle, dentry, inode);
if (err) { if (err) {
...@@ -2068,7 +2065,7 @@ static int ext3_symlink (struct inode * dir, ...@@ -2068,7 +2065,7 @@ static int ext3_symlink (struct inode * dir,
goto out_stop; goto out_stop;
if (l > sizeof (EXT3_I(inode)->i_data)) { if (l > sizeof (EXT3_I(inode)->i_data)) {
inode->i_op = &page_symlink_inode_operations; inode->i_op = &ext3_symlink_inode_operations;
if (ext3_should_writeback_data(inode)) if (ext3_should_writeback_data(inode))
inode->i_mapping->a_ops = &ext3_writeback_aops; inode->i_mapping->a_ops = &ext3_writeback_aops;
else else
...@@ -2284,4 +2281,17 @@ struct inode_operations ext3_dir_inode_operations = { ...@@ -2284,4 +2281,17 @@ struct inode_operations ext3_dir_inode_operations = {
.rmdir = ext3_rmdir, .rmdir = ext3_rmdir,
.mknod = ext3_mknod, .mknod = ext3_mknod,
.rename = ext3_rename, .rename = ext3_rename,
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
}; };
struct inode_operations ext3_special_inode_operations = {
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
};
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "xattr.h"
#ifdef CONFIG_JBD_DEBUG #ifdef CONFIG_JBD_DEBUG
static int ext3_ro_after; /* Make fs read-only after this many jiffies */ static int ext3_ro_after; /* Make fs read-only after this many jiffies */
...@@ -375,6 +376,7 @@ void ext3_put_super (struct super_block * sb) ...@@ -375,6 +376,7 @@ void ext3_put_super (struct super_block * sb)
struct ext3_super_block *es = sbi->s_es; struct ext3_super_block *es = sbi->s_es;
int i; int i;
ext3_xattr_put_super(sb);
journal_destroy(sbi->s_journal); journal_destroy(sbi->s_journal);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
...@@ -551,6 +553,13 @@ static int parse_options (char * options, struct ext3_sb_info *sbi, ...@@ -551,6 +553,13 @@ static int parse_options (char * options, struct ext3_sb_info *sbi,
continue; continue;
if ((value = strchr (this_char, '=')) != NULL) if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0; *value++ = 0;
#ifdef CONFIG_EXT3_FS_XATTR
if (!strcmp (this_char, "user_xattr"))
set_opt (sbi->s_mount_opt, XATTR_USER);
else if (!strcmp (this_char, "nouser_xattr"))
clear_opt (sbi->s_mount_opt, XATTR_USER);
else
#endif
if (!strcmp (this_char, "bsddf")) if (!strcmp (this_char, "bsddf"))
clear_opt (sbi->s_mount_opt, MINIX_DF); clear_opt (sbi->s_mount_opt, MINIX_DF);
else if (!strcmp (this_char, "nouid32")) { else if (!strcmp (this_char, "nouid32")) {
...@@ -1017,6 +1026,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) ...@@ -1017,6 +1026,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, GRPID); set_opt(sbi->s_mount_opt, GRPID);
if (def_mount_opts & EXT3_DEFM_UID16) if (def_mount_opts & EXT3_DEFM_UID16)
set_opt(sbi->s_mount_opt, NO_UID32); set_opt(sbi->s_mount_opt, NO_UID32);
if (def_mount_opts & EXT3_DEFM_XATTR_USER)
set_opt(sbi->s_mount_opt, XATTR_USER);
if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA)
sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA; sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA;
else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED)
...@@ -1840,7 +1851,10 @@ static struct file_system_type ext3_fs_type = { ...@@ -1840,7 +1851,10 @@ static struct file_system_type ext3_fs_type = {
static int __init init_ext3_fs(void) static int __init init_ext3_fs(void)
{ {
int err = init_inodecache(); int err = init_ext3_xattr();
if (err)
return err;
err = init_inodecache();
if (err) if (err)
goto out1; goto out1;
err = register_filesystem(&ext3_fs_type); err = register_filesystem(&ext3_fs_type);
...@@ -1850,6 +1864,7 @@ static int __init init_ext3_fs(void) ...@@ -1850,6 +1864,7 @@ static int __init init_ext3_fs(void)
out: out:
destroy_inodecache(); destroy_inodecache();
out1: out1:
exit_ext3_xattr();
return err; return err;
} }
...@@ -1857,6 +1872,7 @@ static void __exit exit_ext3_fs(void) ...@@ -1857,6 +1872,7 @@ static void __exit exit_ext3_fs(void)
{ {
unregister_filesystem(&ext3_fs_type); unregister_filesystem(&ext3_fs_type);
destroy_inodecache(); destroy_inodecache();
exit_ext3_xattr();
} }
MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/jbd.h> #include <linux/jbd.h>
#include <linux/ext3_fs.h> #include <linux/ext3_fs.h>
#include "xattr.h"
static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen) static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
{ {
...@@ -33,7 +34,20 @@ static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -33,7 +34,20 @@ static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
return vfs_follow_link(nd, (char*)ei->i_data); return vfs_follow_link(nd, (char*)ei->i_data);
} }
struct inode_operations ext3_symlink_inode_operations = {
.readlink = page_readlink,
.follow_link = page_follow_link,
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
};
struct inode_operations ext3_fast_symlink_inode_operations = { struct inode_operations ext3_fast_symlink_inode_operations = {
.readlink = ext3_readlink, /* BKL not held. Don't need */ .readlink = ext3_readlink, /* BKL not held. Don't need */
.follow_link = ext3_follow_link, /* BKL not held. Don't need */ .follow_link = ext3_follow_link, /* BKL not held. Don't need */
.setxattr = ext3_setxattr,
.getxattr = ext3_getxattr,
.listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
}; };
This diff is collapsed.
/*
File: fs/ext3/xattr.h
On-disk format of extended attributes for the ext3 filesystem.
(C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#include <linux/config.h>
#include <linux/xattr.h>
/* Magic value in attribute blocks */
#define EXT3_XATTR_MAGIC 0xEA020000
/* Maximum number of references to one attribute block */
#define EXT3_XATTR_REFCOUNT_MAX 1024
/* Name indexes */
#define EXT3_XATTR_INDEX_MAX 10
#define EXT3_XATTR_INDEX_USER 1
#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2
#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3
struct ext3_xattr_header {
__u32 h_magic; /* magic number for identification */
__u32 h_refcount; /* reference count */
__u32 h_blocks; /* number of disk blocks used */
__u32 h_hash; /* hash value of all attributes */
__u32 h_reserved[4]; /* zero right now */
};
struct ext3_xattr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
__u16 e_value_offs; /* offset in disk block of value */
__u32 e_value_block; /* disk block attribute is stored on (n/i) */
__u32 e_value_size; /* size of attribute value */
__u32 e_hash; /* hash value of name and value */
char e_name[0]; /* attribute name */
};
#define EXT3_XATTR_PAD_BITS 2
#define EXT3_XATTR_PAD (1<<EXT3_XATTR_PAD_BITS)
#define EXT3_XATTR_ROUND (EXT3_XATTR_PAD-1)
#define EXT3_XATTR_LEN(name_len) \
(((name_len) + EXT3_XATTR_ROUND + \
sizeof(struct ext3_xattr_entry)) & ~EXT3_XATTR_ROUND)
#define EXT3_XATTR_NEXT(entry) \
( (struct ext3_xattr_entry *)( \
(char *)(entry) + EXT3_XATTR_LEN((entry)->e_name_len)) )
#define EXT3_XATTR_SIZE(size) \
(((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND)
# ifdef CONFIG_EXT3_FS_XATTR
struct ext3_xattr_handler {
char *prefix;
size_t (*list)(char *list, struct inode *inode, const char *name,
int name_len);
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);
};
extern int ext3_xattr_register(int, struct ext3_xattr_handler *);
extern void ext3_xattr_unregister(int, struct ext3_xattr_handler *);
extern int ext3_setxattr(struct dentry *, const char *, void *, size_t, int);
extern ssize_t ext3_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
extern int ext3_removexattr(struct dentry *, const char *);
extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t);
extern int ext3_xattr_list(struct inode *, char *, size_t);
extern int ext3_xattr_set(handle_t *handle, struct inode *, int, const char *, const void *, size_t, int);
extern void ext3_xattr_delete_inode(handle_t *, struct inode *);
extern void ext3_xattr_put_super(struct super_block *);
extern int init_ext3_xattr(void);
extern void exit_ext3_xattr(void);
# else /* CONFIG_EXT3_FS_XATTR */
# define ext3_setxattr NULL
# define ext3_getxattr NULL
# define ext3_listxattr NULL
# define ext3_removexattr NULL
static inline int
ext3_xattr_get(struct inode *inode, int name_index, const char *name,
void *buffer, size_t size, int flags)
{
return -EOPNOTSUPP;
}
static inline int
ext3_xattr_list(struct inode *inode, void *buffer, size_t size, int flags)
{
return -EOPNOTSUPP;
}
static inline int
ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
const char *name, const void *value, size_t size, int flags)
{
return -EOPNOTSUPP;
}
static inline void
ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
{
}
static inline void
ext3_xattr_put_super(struct super_block *sb)
{
}
static inline int
init_ext3_xattr(void)
{
return 0;
}
static inline void
exit_ext3_xattr(void)
{
}
# endif /* CONFIG_EXT3_FS_XATTR */
extern struct ext3_xattr_handler ext3_xattr_user_handler;
/*
* linux/fs/ext3/xattr_user.c
* Handler for extended user attributes.
*
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include "xattr.h"
#ifdef CONFIG_EXT3_FS_POSIX_ACL
# include "acl.h"
#endif
#define XATTR_USER_PREFIX "user."
static size_t
ext3_xattr_user_list(char *list, struct inode *inode,
const char *name, int name_len)
{
const int prefix_len = sizeof(XATTR_USER_PREFIX)-1;
if (!test_opt(inode->i_sb, XATTR_USER))
return 0;
if (list) {
memcpy(list, XATTR_USER_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
}
return prefix_len + name_len;
}
static int
ext3_xattr_user_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
int error;
if (strcmp(name, "") == 0)
return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER))
return -EOPNOTSUPP;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
error = ext3_permission_locked(inode, MAY_READ);
#else
error = permission(inode, MAY_READ);
#endif
if (error)
return error;
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name,
buffer, size);
}
static int
ext3_xattr_user_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
handle_t *handle;
int error;
if (strcmp(name, "") == 0)
return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER))
return -EOPNOTSUPP;
if ( !S_ISREG(inode->i_mode) &&
(!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
return -EPERM;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
error = ext3_permission_locked(inode, MAY_WRITE);
#else
error = permission(inode, MAY_WRITE);
#endif
if (error)
return error;
lock_kernel();
handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
if (IS_ERR(handle))
return PTR_ERR(handle);
error = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_USER, name,
value, size, flags);
ext3_journal_stop(handle, inode);
unlock_kernel();
return error;
}
struct ext3_xattr_handler ext3_xattr_user_handler = {
prefix: XATTR_USER_PREFIX,
list: ext3_xattr_user_list,
get: ext3_xattr_user_get,
set: ext3_xattr_user_set,
};
...@@ -64,8 +64,6 @@ ...@@ -64,8 +64,6 @@
*/ */
#define EXT3_BAD_INO 1 /* Bad blocks inode */ #define EXT3_BAD_INO 1 /* Bad blocks inode */
#define EXT3_ROOT_INO 2 /* Root inode */ #define EXT3_ROOT_INO 2 /* Root inode */
#define EXT3_ACL_IDX_INO 3 /* ACL inode */
#define EXT3_ACL_DATA_INO 4 /* ACL inode */
#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ #define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ #define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */
...@@ -95,7 +93,6 @@ ...@@ -95,7 +93,6 @@
#else #else
# define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) # define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#endif #endif
#define EXT3_ACLE_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry))
#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) #define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32))
#ifdef __KERNEL__ #ifdef __KERNEL__
# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) # define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
...@@ -129,28 +126,6 @@ ...@@ -129,28 +126,6 @@
# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s)) # define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s))
#endif #endif
/*
* ACL structures
*/
struct ext3_acl_header /* Header of Access Control Lists */
{
__u32 aclh_size;
__u32 aclh_file_count;
__u32 aclh_acle_count;
__u32 aclh_first_acle;
};
struct ext3_acl_entry /* Access Control List Entry */
{
__u32 acle_size;
__u16 acle_perms; /* Access permissions */
__u16 acle_type; /* Type of entry */
__u16 acle_tag; /* User or group identity */
__u16 acle_pad1;
__u32 acle_next; /* Pointer on next entry for the */
/* same inode or on next free entry */
};
/* /*
* Structure of a blocks group descriptor * Structure of a blocks group descriptor
*/ */
...@@ -347,6 +322,7 @@ struct ext3_inode { ...@@ -347,6 +322,7 @@ struct ext3_inode {
#define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */
#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ #define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H #ifndef _LINUX_EXT2_FS_H
...@@ -532,7 +508,7 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode) ...@@ -532,7 +508,7 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT3_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT3_FEATURE_COMPAT_SUPP 0 #define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT2_FEATURE_INCOMPAT_META_BG) EXT2_FEATURE_INCOMPAT_META_BG)
#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \
...@@ -731,6 +707,7 @@ extern unsigned long ext3_count_free (struct buffer_head *, unsigned); ...@@ -731,6 +707,7 @@ extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
/* inode.c */ /* inode.c */
extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
...@@ -799,8 +776,10 @@ extern struct address_space_operations ext3_writeback_aops; ...@@ -799,8 +776,10 @@ extern struct address_space_operations ext3_writeback_aops;
/* namei.c */ /* namei.c */
extern struct inode_operations ext3_dir_inode_operations; extern struct inode_operations ext3_dir_inode_operations;
extern struct inode_operations ext3_special_inode_operations;
/* symlink.c */ /* symlink.c */
extern struct inode_operations ext3_symlink_inode_operations;
extern struct inode_operations ext3_fast_symlink_inode_operations; extern struct inode_operations ext3_fast_symlink_inode_operations;
......
...@@ -30,13 +30,19 @@ ...@@ -30,13 +30,19 @@
#define EXT3_SINGLEDATA_TRANS_BLOCKS 8 #define EXT3_SINGLEDATA_TRANS_BLOCKS 8
/* Extended attributes may touch two data buffers, two bitmap buffers,
* and two group and summaries. */
#define EXT3_XATTR_TRANS_BLOCKS 8
/* Define the minimum size for a transaction which modifies data. This /* Define the minimum size for a transaction which modifies data. This
* needs to take into account the fact that we may end up modifying two * needs to take into account the fact that we may end up modifying two
* quota files too (one for the group, one for the user quota). The * quota files too (one for the group, one for the user quota). The
* superblock only gets updated once, of course, so don't bother * superblock only gets updated once, of course, so don't bother
* counting that again for the quota updates. */ * counting that again for the quota updates. */
#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2) #define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
EXT3_XATTR_TRANS_BLOCKS - 2)
extern int ext3_writepage_trans_blocks(struct inode *inode); extern int ext3_writepage_trans_blocks(struct inode *inode);
......
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