diff -rup -X dontdiff linux/fs/reiserfs/dir.c linux.patched/fs/reiserfs/dir.c
--- linux/fs/reiserfs/dir.c     Wed Nov 21 12:02:35 2001
+++ linux.patched/fs/reiserfs/dir.c     Tue Nov 20 22:47:11 2001
@@ -20,6 +20,7 @@ struct file_operations reiserfs_dir_oper
    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) {
diff -rup -X dontdiff linux/fs/reiserfs/inode.c linux.patched/fs/reiserfs/inode.c
--- linux/fs/reiserfs/inode.c   Wed Nov 21 12:02:35 2001
+++ linux.patched/fs/reiserfs/inode.c   Wed Nov 21 12:26:25 2001
@@ -910,6 +910,9 @@ static void init_inode (struct inode * i

        rdev = sd_v1_rdev(sd);
       inode->u.reiserfs_i.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 */
+       inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
    } else {
       // new stat data found, but object may have old items
       // (directories and symlinks)
@@ -937,10 +940,12 @@ static void init_inode (struct inode * i
           set_inode_item_key_version (inode, KEY_FORMAT_3_5);
       else
            set_inode_item_key_version (inode, KEY_FORMAT_3_6);
-    }

-    /* nopack = 0, by default */
-    inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
+       /* read persistemt inode attributes from sd and initalise
+          generic inode flags from them */
+       inode -> u.reiserfs_i.i_attrs = sd_v2_attrs( sd );
+       sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );
+    }

    pathrelse (path);
    if (S_ISREG (inode->i_mode)) {
@@ -964,6 +969,7 @@ static void init_inode (struct inode * i
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 );
@@ -974,13 +980,13 @@ static void inode2sd (void * sd, struct
    set_sd_v2_atime(sd_v2, inode->i_atime );
    set_sd_v2_ctime(sd_v2, inode->i_ctime );
    set_sd_v2_blocks(sd_v2, inode->i_blocks );
-    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
        set_sd_v2_rdev(sd_v2, inode->i_rdev );
-}
    else
-    {
        set_sd_v2_generation(sd_v2, inode->i_generation);
-    }
+    flags = inode -> u.reiserfs_i.i_attrs;
+    i_attrs_to_sd_attrs( inode, &flags );
+    set_sd_v2_attrs( sd_v2, flags );
}


@@ -1450,7 +1456,9 @@ struct inode * reiserfs_new_inode (struc
    }

    sb = dir->i_sb;
-    inode->i_flags = 0;//inode->i_sb->s_flags;
+    inode -> u.reiserfs_i.i_attrs =
+           dir -> u.reiserfs_i.i_attrs & REISERFS_INHERIT_MASK;
+    sd_attrs_to_i_attrs( inode -> u.reiserfs_i.i_attrs, inode );

    /* item head of new item */
    ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
@@ -1509,6 +1517,10 @@ struct inode * reiserfs_new_inode (struc
    } else
       inode->i_gid = current->fsgid;

+    /* 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;
@@ -2028,6 +2040,50 @@ static int reiserfs_commit_write(struct
       unlock_kernel();
    }
    return ret ;
+}
+
+void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
+{
+       if( !reiserfs_noattrs( 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 )
+                       inode->u.reiserfs_i.i_flags |= i_nopack_mask;
+               else
+                       inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
+       }
+}
+
+void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
+{
+       if( !reiserfs_noattrs( 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( inode->u.reiserfs_i.i_flags & i_nopack_mask )
+                       *sd_attrs |= REISERFS_NOTAIL_FL;
+               else
+                       *sd_attrs &= ~REISERFS_NOTAIL_FL;
+       }
}

struct address_space_operations reiserfs_address_space_operations = {
diff -rup -X dontdiff linux/fs/reiserfs/ioctl.c linux.patched/fs/reiserfs/ioctl.c
--- linux/fs/reiserfs/ioctl.c   Wed Nov 21 12:02:35 2001
+++ linux.patched/fs/reiserfs/ioctl.c   Tue Nov 20 22:47:11 2001
@@ -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 ([email protected]) */
+       case REISERFS_IOC_GETFLAGS:
+               flags = inode -> u.reiserfs_i.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 );
+               inode -> u.reiserfs_i.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;
       }
}
@@ -43,7 +96,8 @@ int reiserfs_unpack (struct inode * inod
    unsigned long blocksize = inode->i_sb->s_blocksize ;

    if (inode->i_size == 0) {
-        return -EINVAL ;
+        inode->u.reiserfs_i.i_flags |= i_nopack_mask;
+        return 0 ;
    }
    /* ioctl already done */
    if (inode->u.reiserfs_i.i_flags & i_nopack_mask) {
diff -rup -X dontdiff linux/fs/reiserfs/super.c linux.patched/fs/reiserfs/super.c
--- linux/fs/reiserfs/super.c   Wed Nov 21 12:02:35 2001
+++ linux.patched/fs/reiserfs/super.c   Wed Nov 21 12:27:27 2001
@@ -472,6 +472,8 @@ static int parse_options (char * options
               printk("reiserfs: hash option requires a value\n");
               return 0 ;
           }
+       } else if (!strcmp (this_char, "noattrs")) {
+           set_bit (REISERFS_NOATTRS, mount_options);
       } else {
           printk ("reiserfs: Unrecognized mount option %s\n", this_char);
           return 0;
Only in linux.patched/include/linux: modules
diff -rup -X dontdiff linux/include/linux/reiserfs_fs.h linux.patched/include/linux/reiserfs_fs.h
--- linux/include/linux/reiserfs_fs.h   Wed Nov 21 12:02:35 2001
+++ linux.patched/include/linux/reiserfs_fs.h   Wed Nov 21 12:38:59 2001
@@ -718,11 +718,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 */
@@ -775,6 +805,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))


/***************************************************************************/
@@ -1701,6 +1733,9 @@ struct inode * reiserfs_new_inode (struc
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,
@@ -1918,6 +1953,12 @@ int reiserfs_unpack (struct inode * inod

/* 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

#endif /* _LINUX_REISER_FS_H */

diff -rup -X dontdiff linux/include/linux/reiserfs_fs_i.h linux.patched/include/linux/reiserfs_fs_i.h
--- linux/include/linux/reiserfs_fs_i.h Wed Nov 21 12:02:35 2001
+++ linux.patched/include/linux/reiserfs_fs_i.h Wed Nov 21 12:33:57 2001
@@ -33,6 +33,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
diff -rup -X dontdiff linux/include/linux/reiserfs_fs_sb.h linux.patched/include/linux/reiserfs_fs_sb.h
--- linux/include/linux/reiserfs_fs_sb.h        Wed Nov 21 12:02:23 2001
+++ linux.patched/include/linux/reiserfs_fs_sb.h        Wed Nov 21 12:33:57 2001
@@ -462,6 +462,8 @@ struct reiserfs_sb_info
#define REISERFS_TEST3 13
#define REISERFS_TEST4 14

+#define REISERFS_NOATTRS (15)
+
#define reiserfs_r5_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_R5_HASH))
#define reiserfs_rupasov_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_RUPASOV_HASH))
#define reiserfs_tea_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_TEA_HASH))
@@ -474,8 +476,8 @@ struct reiserfs_sb_info
#define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
#define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
#define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
+#define reiserfs_noattrs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOATTRS))
#define old_format_only(s) ((SB_VERSION(s) != REISERFS_VERSION_2) && !((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT)))
-

void reiserfs_file_buffer (struct buffer_head * bh, int list);
int reiserfs_is_super(struct super_block *s)  ;