Commit 37c90629 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reiserfs: inode attributes support.

From: Oleg Drokin <green@namesys.com>

This is a forward port of 2.4's inode attributes support for reiserfs.
Original implementation for 2.4 was performed by Nikita Danilov.

In order to enable this support, one must use "attrs" mount options, eg:

	mount /dev/hda1 /mount/pont -t reiserfs -o attrs

Also either the filesystem must have been created with a recent mkreiserfs
or must have been modified by a recent version of reiserfsck with its
"--clean-attributes" option.

If that is not done, attributes support will not be enabled and a kernel
message will be printed.  This is necessary because old kernels left random
garbage in the place where these attributes now live.

These attributes are totally compatible with ext2's ones.  You can
manipulate them with chattr/lsattr etc.

Additionally the chattr 'd' option may be used to disable tail packing on a
specific file or a directory tree.  (The 'd' option normally means "don't
dump".  reiserfs has overloaded it).
parent 0c85cefd
......@@ -21,6 +21,7 @@ struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
.ioctl = reiserfs_ioctl,
};
int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
......
......@@ -918,8 +918,6 @@ static void init_inode (struct inode * inode, struct path * path)
REISERFS_I(inode)->i_prealloc_count = 0;
REISERFS_I(inode)->i_trans_id = 0;
REISERFS_I(inode)->i_trans_index = 0;
/* nopack = 0, by default */
REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
if (stat_data_v1 (ih)) {
struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
......@@ -954,6 +952,9 @@ static void init_inode (struct inode * inode, struct path * path)
rdev = sd_v1_rdev(sd);
REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
/* nopack is initially zero for v1 objects. For v2 objects,
nopack is initialised from sd_attrs */
REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
} else {
// new stat data found, but object may have old items
// (directories and symlinks)
......@@ -983,6 +984,10 @@ static void init_inode (struct inode * inode, struct path * path)
set_inode_item_key_version (inode, KEY_FORMAT_3_6);
REISERFS_I(inode)->i_first_direct_byte = 0;
set_inode_sd_version (inode, STAT_DATA_V2);
/* read persistent inode attributes from sd and initalise
generic inode flags from them */
REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );
sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );
}
pathrelse (path);
......@@ -1007,6 +1012,7 @@ static void init_inode (struct inode * inode, struct path * path)
static void inode2sd (void * sd, struct inode * inode)
{
struct stat_data * sd_v2 = (struct stat_data *)sd;
__u16 flags;
set_sd_v2_mode(sd_v2, inode->i_mode );
set_sd_v2_nlink(sd_v2, inode->i_nlink );
......@@ -1017,13 +1023,13 @@ static void inode2sd (void * sd, struct inode * inode)
set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec );
set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );
set_sd_v2_blocks(sd_v2, inode->i_blocks );
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
set_sd_v2_rdev(sd_v2, kdev_t_to_nr(inode->i_rdev) );
}
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
set_sd_v2_rdev(sd_v2, kdev_t_to_nr(inode->i_rdev) );
else
{
set_sd_v2_generation(sd_v2, inode->i_generation);
}
set_sd_v2_generation(sd_v2, inode->i_generation);
flags = REISERFS_I(inode)->i_attrs;
i_attrs_to_sd_attrs( inode, &flags );
set_sd_v2_attrs( sd_v2, flags );
}
......@@ -1553,6 +1559,10 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
/* uid and gid must already be set by the caller for quota init */
/* symlink cannot be immutable or append only, right? */
if( S_ISLNK( inode -> i_mode ) )
inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_size = i_size;
inode->i_blocks = (inode->i_size + 511) >> 9;
......@@ -1565,6 +1575,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
REISERFS_I(inode)->i_prealloc_count = 0;
REISERFS_I(inode)->i_trans_id = 0;
REISERFS_I(inode)->i_trans_index = 0;
REISERFS_I(inode)->i_attrs =
REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode );
if (old_format_only (sb))
make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
......@@ -2210,6 +2223,50 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
return ret ;
}
void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
{
if( reiserfs_attrs( inode -> i_sb ) ) {
if( sd_attrs & REISERFS_SYNC_FL )
inode -> i_flags |= S_SYNC;
else
inode -> i_flags &= ~S_SYNC;
if( sd_attrs & REISERFS_IMMUTABLE_FL )
inode -> i_flags |= S_IMMUTABLE;
else
inode -> i_flags &= ~S_IMMUTABLE;
if( sd_attrs & REISERFS_NOATIME_FL )
inode -> i_flags |= S_NOATIME;
else
inode -> i_flags &= ~S_NOATIME;
if( sd_attrs & REISERFS_NOTAIL_FL )
REISERFS_I(inode)->i_flags |= i_nopack_mask;
else
REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
}
}
void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
{
if( reiserfs_attrs( inode -> i_sb ) ) {
if( inode -> i_flags & S_IMMUTABLE )
*sd_attrs |= REISERFS_IMMUTABLE_FL;
else
*sd_attrs &= ~REISERFS_IMMUTABLE_FL;
if( inode -> i_flags & S_SYNC )
*sd_attrs |= REISERFS_SYNC_FL;
else
*sd_attrs &= ~REISERFS_SYNC_FL;
if( inode -> i_flags & S_NOATIME )
*sd_attrs |= REISERFS_NOATIME_FL;
else
*sd_attrs &= ~REISERFS_NOATIME_FL;
if( REISERFS_I(inode)->i_flags & i_nopack_mask )
*sd_attrs |= REISERFS_NOTAIL_FL;
else
*sd_attrs &= ~REISERFS_NOTAIL_FL;
}
}
/*
* Returns 1 if the page's buffers were dropped. The page is locked.
*
......
......@@ -14,17 +14,70 @@
** supported commands:
** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
** and prevent packing file (argument arg has to be non-zero)
** 2) That's all for a while ...
** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
** 3) That's all for a while ...
*/
int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
unsigned int flags;
switch (cmd) {
case REISERFS_IOC_UNPACK:
if( S_ISREG( inode -> i_mode ) ) {
if (arg)
return reiserfs_unpack (inode, filp);
else
return 0;
} else
return -ENOTTY;
/* following two cases are taken from fs/ext2/ioctl.c by Remy
Card (card@masi.ibp.fr) */
case REISERFS_IOC_GETFLAGS:
flags = REISERFS_I(inode) -> i_attrs;
i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
return put_user(flags, (int *) arg);
case REISERFS_IOC_SETFLAGS: {
if (IS_RDONLY(inode))
return -EROFS;
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (get_user(flags, (int *) arg))
return -EFAULT;
if ( ( flags & REISERFS_IMMUTABLE_FL ) &&
!capable( CAP_LINUX_IMMUTABLE ) )
return -EPERM;
default:
if( ( flags & REISERFS_NOTAIL_FL ) &&
S_ISREG( inode -> i_mode ) ) {
int result;
result = reiserfs_unpack( inode, filp );
if( result )
return result;
}
sd_attrs_to_i_attrs( flags, inode );
REISERFS_I(inode) -> i_attrs = flags;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
return 0;
}
case REISERFS_IOC_GETVERSION:
return put_user(inode->i_generation, (int *) arg);
case REISERFS_IOC_SETVERSION:
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
if (get_user(inode->i_generation, (int *) arg))
return -EFAULT;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
return 0;
default:
return -ENOTTY;
}
}
......@@ -32,7 +85,7 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
/*
** reiserfs_unpack
** Function try to convert tail from direct item into indirect.
** It set up nopack attribute in the inode.u.reiserfs_i.nopack
** It set up nopack attribute in the REISERFS_I(inode)->nopack
*/
int reiserfs_unpack (struct inode * inode, struct file * filp)
{
......@@ -43,7 +96,8 @@ int reiserfs_unpack (struct inode * inode, struct file * filp)
unsigned long blocksize = inode->i_sb->s_blocksize ;
if (inode->i_size == 0) {
return -EINVAL ;
REISERFS_I(inode)->i_flags |= i_nopack_mask;
return 0 ;
}
/* ioctl already done */
if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
......
......@@ -350,6 +350,7 @@ int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
struct reiserfs_sb_info *sb_info;
struct reiserfs_super_block *rs;
int hash_code;
__u32 flags;
int len = 0;
sb = procinfo_prologue((int)data);
......@@ -358,6 +359,7 @@ int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
sb_info = REISERFS_SB(sb);
rs = sb_info -> s_rs;
hash_code = DFL( s_hash_function_code );
flags = DJF( s_flags );
len += sprintf( &buffer[ len ],
"block_count: \t%i\n"
......@@ -373,6 +375,7 @@ int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
"tree_height: \t%i\n"
"bmap_nr: \t%i\n"
"version: \t%i\n"
"flags: \t%x[%s]\n"
"reserved_for_journal: \t%i\n",
DFL( s_block_count ),
......@@ -391,6 +394,9 @@ int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
DF( s_tree_height ),
DF( s_bmap_nr ),
DF( s_version ),
flags,
( flags & reiserfs_attrs_cleared )
? "attrs_cleared" : "",
DF (s_reserved_for_journal));
procinfo_epilogue( sb );
......
......@@ -708,6 +708,24 @@ for old setups still work */
return 1;
}
static void handle_attrs( struct super_block *s )
{
struct reiserfs_super_block * rs;
if( reiserfs_attrs( s ) ) {
rs = SB_DISK_SUPER_BLOCK (s);
if( old_format_only(s) ) {
reiserfs_warning( "reiserfs: cannot support attributes on 3.5.x disk format\n" );
REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
return;
}
if( !( le32_to_cpu( rs -> s_flags ) & reiserfs_attrs_cleared ) ) {
reiserfs_warning( "reiserfs: cannot support attributes until flag is set in super-block\n" );
REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
}
}
}
static int reiserfs_remount (struct super_block * s, int * mount_flags, char * arg)
{
struct reiserfs_super_block * rs;
......@@ -720,6 +738,8 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL))
return -EINVAL;
handle_attrs( s );
if(blocks) {
int rc = reiserfs_resize(s, blocks);
if (rc != 0)
......@@ -1319,6 +1339,8 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
// mark hash in super block: it could be unset. overwrite should be ok
set_sb_hash_function_code( rs, function2code(sbi->s_hash_function ) );
handle_attrs( s );
reiserfs_proc_info_init( s );
reiserfs_proc_register( s, "version", reiserfs_version_in_proc );
reiserfs_proc_register( s, "super", reiserfs_super_in_proc );
......
......@@ -872,11 +872,41 @@ struct stat_data_v1
#define set_sd_v1_first_direct_byte(sdp,v) \
((sdp)->sd_first_direct_byte = cpu_to_le32(v))
#include <linux/ext2_fs.h>
/* inode flags stored in sd_attrs (nee sd_reserved) */
/* we want common flags to have the same values as in ext2,
so chattr(1) will work without problems */
#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
#define REISERFS_SYNC_FL EXT2_SYNC_FL
#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
#define REISERFS_SECRM_FL EXT2_SECRM_FL
#define REISERFS_UNRM_FL EXT2_UNRM_FL
#define REISERFS_COMPR_FL EXT2_COMPR_FL
/* persistent flag to disable tails on per-file basic.
Note, that is inheritable: mark directory with this and
all new files inside will not have tails.
Teodore Tso allocated EXT2_NODUMP_FL (0x00008000) for this. Change
numeric constant to ext2 macro when available. */
#define REISERFS_NOTAIL_FL (0x00008000) /* EXT2_NOTAIL_FL */
/* persistent flags that file inherits from the parent directory */
#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \
REISERFS_SYNC_FL | \
REISERFS_NOATIME_FL | \
REISERFS_NODUMP_FL | \
REISERFS_SECRM_FL | \
REISERFS_COMPR_FL | \
REISERFS_NOTAIL_FL )
/* Stat Data on disk (reiserfs version of UFS disk inode minus the
address blocks) */
struct stat_data {
__u16 sd_mode; /* file type, permissions */
__u16 sd_reserved;
__u16 sd_attrs; /* persistent inode flags */
__u32 sd_nlink; /* number of hard links */
__u64 sd_size; /* file size */
__u32 sd_uid; /* owner */
......@@ -929,6 +959,8 @@ struct stat_data {
#define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v))
#define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation))
#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs))
#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v))
/***************************************************************************/
......@@ -1871,6 +1903,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
void reiserfs_update_sd (struct reiserfs_transaction_handle *th, 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 );
/* namei.c */
inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
int search_by_entry_key (struct super_block * sb, const struct cpu_key * key,
......@@ -2145,6 +2180,12 @@ int reiserfs_unpack (struct inode * inode, struct file * filp);
/* ioctl's command */
#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
/* define following flags to be the same as in ext2, so that chattr(1),
lsattr(1) will work with us. */
#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION
#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION
/* Locking primitives */
/* Right now we are still falling back to (un)lock_kernel, but eventually that
......
......@@ -32,6 +32,9 @@ struct reiserfs_inode_info {
__u32 i_first_direct_byte; // offset of first byte stored in direct item.
/* copy of persistent inode flags read from sd_attrs. */
__u32 i_attrs;
int i_prealloc_block; /* first unused block of a sequence of unused blocks */
int i_prealloc_count; /* length of that sequence */
struct list_head i_prealloc_list; /* per-transaction list of inodes which
......
......@@ -8,6 +8,9 @@
#include <linux/workqueue.h>
#endif
typedef enum {
reiserfs_attrs_cleared = 0x00000001,
} reiserfs_super_block_flags;
/* struct reiserfs_super_block accessors/mutators
* since this is a disk structure, it will always be in
......@@ -436,7 +439,6 @@ struct reiserfs_sb_info
#define REISERFS_NO_BORDER 11
#define REISERFS_NO_UNHASHED_RELOCATION 12
#define REISERFS_HASHED_RELOCATION 13
#define REISERFS_TEST4 14
#define REISERFS_ATTRS 15
......@@ -458,6 +460,7 @@ struct reiserfs_sb_info
#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
#define reiserfs_dont_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NOLOG))
#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS))
#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT))
......
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