ocfs2: add ext2 attributes
authorHerbert Poetzl <herbert@13thfloor.at>
Tue, 4 Jul 2006 00:27:12 +0000 (17:27 -0700)
committerMark Fasheh <mark.fasheh@oracle.com>
Wed, 20 Sep 2006 22:48:39 +0000 (15:48 -0700)
Support immutable, and other attributes.

Some renaming and other minor fixes done by myself.

Signed-off-by: Herbert Poetzl <herbert@13thfloor.at>
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
fs/ocfs2/Makefile
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/ioctl.c [new file with mode: 0644]
fs/ocfs2/ioctl.h [new file with mode: 0644]
fs/ocfs2/ocfs2_fs.h

index 7d3be84..9fb8132 100644 (file)
@@ -16,6 +16,7 @@ ocfs2-objs := \
        file.o                  \
        heartbeat.o             \
        inode.o                 \
+       ioctl.o                 \
        journal.o               \
        localalloc.o            \
        mmap.o                  \
index 762eb1f..151b417 100644 (file)
@@ -1330,6 +1330,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
                cpu_to_be64(ocfs2_pack_timespec(&inode->i_ctime));
        lvb->lvb_imtime_packed =
                cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
+       lvb->lvb_iattr    = cpu_to_be32(oi->ip_attr);
 
        mlog_meta_lvb(0, lockres);
 
@@ -1360,6 +1361,9 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
        oi->ip_clusters = be32_to_cpu(lvb->lvb_iclusters);
        i_size_write(inode, be64_to_cpu(lvb->lvb_isize));
 
+       oi->ip_attr = be32_to_cpu(lvb->lvb_iattr);
+       ocfs2_set_inode_flags(inode);
+
        /* fast-symlinks are a special case */
        if (S_ISLNK(inode->i_mode) && !oi->ip_clusters)
                inode->i_blocks = 0;
@@ -2899,8 +2903,9 @@ void ocfs2_dump_meta_lvb_info(u64 level,
             be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),
             be16_to_cpu(lvb->lvb_imode));
        mlog(level, "nlink %u, atime_packed 0x%llx, ctime_packed 0x%llx, "
-            "mtime_packed 0x%llx\n", be16_to_cpu(lvb->lvb_inlink),
+            "mtime_packed 0x%llx iattr 0x%x\n", be16_to_cpu(lvb->lvb_inlink),
             (long long)be64_to_cpu(lvb->lvb_iatime_packed),
             (long long)be64_to_cpu(lvb->lvb_ictime_packed),
-            (long long)be64_to_cpu(lvb->lvb_imtime_packed));
+            (long long)be64_to_cpu(lvb->lvb_imtime_packed),
+            be32_to_cpu(lvb->lvb_iattr));
 }
index 8f2d1db..243ae86 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef DLMGLUE_H
 #define DLMGLUE_H
 
-#define OCFS2_LVB_VERSION 2
+#define OCFS2_LVB_VERSION 3
 
 struct ocfs2_meta_lvb {
        __be32       lvb_version;
@@ -40,7 +40,8 @@ struct ocfs2_meta_lvb {
        __be64       lvb_isize;
        __be16       lvb_imode;
        __be16       lvb_inlink;
-       __be32       lvb_reserved[3];
+       __be32       lvb_iattr;
+       __be32       lvb_reserved[2];
 };
 
 /* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */
index a9559c8..2bbfa17 100644 (file)
@@ -44,6 +44,7 @@
 #include "file.h"
 #include "sysfile.h"
 #include "inode.h"
+#include "ioctl.h"
 #include "journal.h"
 #include "mmap.h"
 #include "suballoc.h"
@@ -1227,10 +1228,12 @@ const struct file_operations ocfs2_fops = {
        .open           = ocfs2_file_open,
        .aio_read       = ocfs2_file_aio_read,
        .aio_write      = ocfs2_file_aio_write,
+       .ioctl          = ocfs2_ioctl,
 };
 
 const struct file_operations ocfs2_dops = {
        .read           = generic_read_dir,
        .readdir        = ocfs2_readdir,
        .fsync          = ocfs2_sync_file,
+       .ioctl          = ocfs2_ioctl,
 };
index 327a5b7..3f496c4 100644 (file)
@@ -71,6 +71,26 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
                                    struct inode *inode,
                                    struct buffer_head *fe_bh);
 
+void ocfs2_set_inode_flags(struct inode *inode)
+{
+       unsigned int flags = OCFS2_I(inode)->ip_attr;
+
+       inode->i_flags &= ~(S_IMMUTABLE |
+               S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC);
+
+       if (flags & OCFS2_IMMUTABLE_FL)
+               inode->i_flags |= S_IMMUTABLE;
+
+       if (flags & OCFS2_SYNC_FL)
+               inode->i_flags |= S_SYNC;
+       if (flags & OCFS2_APPEND_FL)
+               inode->i_flags |= S_APPEND;
+       if (flags & OCFS2_NOATIME_FL)
+               inode->i_flags |= S_NOATIME;
+       if (flags & OCFS2_DIRSYNC_FL)
+               inode->i_flags |= S_DIRSYNC;
+}
+
 struct inode *ocfs2_ilookup_for_vote(struct ocfs2_super *osb,
                                     u64 blkno,
                                     int delete_vote)
@@ -260,7 +280,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                inode->i_blocks =
                        ocfs2_align_bytes_to_sectors(le64_to_cpu(fe->i_size));
        inode->i_mapping->a_ops = &ocfs2_aops;
-       inode->i_flags |= S_NOATIME;
        inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime);
        inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec);
        inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime);
@@ -276,6 +295,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
 
        OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
        OCFS2_I(inode)->ip_orphaned_slot = OCFS2_INVALID_SLOT;
+       OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
 
        if (create_ino)
                inode->i_ino = ino_from_blkno(inode->i_sb,
@@ -330,6 +350,9 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
        ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres,
                                  OCFS2_LOCK_TYPE_DATA, inode);
 
+       ocfs2_set_inode_flags(inode);
+       inode->i_flags |= S_NOATIME;
+
        status = 0;
 bail:
        mlog_exit(status);
@@ -1131,6 +1154,7 @@ int ocfs2_mark_inode_dirty(struct ocfs2_journal_handle *handle,
 
        spin_lock(&OCFS2_I(inode)->ip_lock);
        fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
+       fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
        spin_unlock(&OCFS2_I(inode)->ip_lock);
 
        fe->i_size = cpu_to_le64(i_size_read(inode));
@@ -1169,6 +1193,8 @@ void ocfs2_refresh_inode(struct inode *inode,
        spin_lock(&OCFS2_I(inode)->ip_lock);
 
        OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
+       OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+       ocfs2_set_inode_flags(inode);
        i_size_write(inode, le64_to_cpu(fe->i_size));
        inode->i_nlink = le16_to_cpu(fe->i_links_count);
        inode->i_uid = le32_to_cpu(fe->i_uid);
index 35140f6..4d1e539 100644 (file)
@@ -56,6 +56,7 @@ struct ocfs2_inode_info
        struct ocfs2_journal_handle     *ip_handle;
 
        u32                             ip_flags; /* see below */
+       u32                             ip_attr; /* inode attributes */
 
        /* protected by recovery_lock. */
        struct inode                    *ip_next_orphan;
@@ -142,4 +143,6 @@ int ocfs2_mark_inode_dirty(struct ocfs2_journal_handle *handle,
 int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb);
 int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
 
+void ocfs2_set_inode_flags(struct inode *inode);
+
 #endif /* OCFS2_INODE_H */
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
new file mode 100644 (file)
index 0000000..68f4806
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * linux/fs/ocfs2/ioctl.c
+ *
+ * Copyright (C) 2006 Herbert Poetzl
+ * adapted from Remy Card's ext2/ioctl.c
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+
+#define MLOG_MASK_PREFIX ML_INODE
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "alloc.h"
+#include "dlmglue.h"
+#include "inode.h"
+#include "journal.h"
+
+#include "ocfs2_fs.h"
+#include <linux/ext2_fs.h>
+
+static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
+{
+       int status;
+
+       status = ocfs2_meta_lock(inode, NULL, NULL, 0);
+       if (status < 0) {
+               mlog_errno(status);
+               return status;
+       }
+       *flags = OCFS2_I(inode)->ip_attr;
+       ocfs2_meta_unlock(inode, 0);
+
+       mlog_exit(status);
+       return status;
+}
+
+static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
+                               unsigned mask)
+{
+       struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_journal_handle *handle = NULL;
+       struct buffer_head *bh = NULL;
+       unsigned oldflags;
+       int status;
+
+       mutex_lock(&inode->i_mutex);
+
+       status = ocfs2_meta_lock(inode, NULL, &bh, 1);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       status = -EROFS;
+       if (IS_RDONLY(inode))
+               goto bail_unlock;
+
+       status = -EACCES;
+       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               goto bail_unlock;
+
+       if (!S_ISDIR(inode->i_mode))
+               flags &= ~OCFS2_DIRSYNC_FL;
+
+       handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               mlog_errno(status);
+               goto bail_unlock;
+       }
+
+       oldflags = ocfs2_inode->ip_attr;
+       flags = flags & mask;
+       flags |= oldflags & ~mask;
+
+       /*
+        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+        * the relevant capability.
+        */
+       status = -EPERM;
+       if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
+               (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
+               if (!capable(CAP_LINUX_IMMUTABLE))
+                       goto bail_unlock;
+       }
+
+       ocfs2_inode->ip_attr = flags;
+       ocfs2_set_inode_flags(inode);
+
+       status = ocfs2_mark_inode_dirty(handle, inode, bh);
+       if (status < 0)
+               mlog_errno(status);
+
+       ocfs2_commit_trans(handle);
+bail_unlock:
+       ocfs2_meta_unlock(inode, 1);
+bail:
+       mutex_unlock(&inode->i_mutex);
+
+       if (bh)
+               brelse(bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+int ocfs2_ioctl(struct inode * inode, struct file * filp,
+       unsigned int cmd, unsigned long arg)
+{
+       unsigned int flags;
+       int status;
+
+       switch (cmd) {
+       case OCFS2_IOC_GETFLAGS:
+               status = ocfs2_get_inode_attr(inode, &flags);
+               if (status < 0)
+                       return status;
+
+               flags &= OCFS2_FL_VISIBLE;
+               return put_user(flags, (int __user *) arg);
+       case OCFS2_IOC_SETFLAGS:
+               if (get_user(flags, (int __user *) arg))
+                       return -EFAULT;
+
+               return ocfs2_set_inode_attr(inode, flags,
+                       OCFS2_FL_MODIFIABLE);
+       default:
+               return -ENOTTY;
+       }
+}
+
diff --git a/fs/ocfs2/ioctl.h b/fs/ocfs2/ioctl.h
new file mode 100644 (file)
index 0000000..4a7c829
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * ioctl.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2006 Herbert Poetzl
+ *
+ */
+
+#ifndef OCFS2_IOCTL_H
+#define OCFS2_IOCTL_H
+
+int ocfs2_ioctl(struct inode * inode, struct file * filp,
+       unsigned int cmd, unsigned long arg);
+
+#endif /* OCFS2_IOCTL_H */
index c5b1ac5..3330a5d 100644 (file)
 #define OCFS2_CHAIN_FL         (0x00000400)    /* Chain allocator */
 #define OCFS2_DEALLOC_FL       (0x00000800)    /* Truncate log */
 
+/* Inode attributes, keep in sync with EXT2 */
+#define OCFS2_SECRM_FL         (0x00000001)    /* Secure deletion */
+#define OCFS2_UNRM_FL          (0x00000002)    /* Undelete */
+#define OCFS2_COMPR_FL         (0x00000004)    /* Compress file */
+#define OCFS2_SYNC_FL          (0x00000008)    /* Synchronous updates */
+#define OCFS2_IMMUTABLE_FL     (0x00000010)    /* Immutable file */
+#define OCFS2_APPEND_FL                (0x00000020)    /* writes to file may only append */
+#define OCFS2_NODUMP_FL                (0x00000040)    /* do not dump file */
+#define OCFS2_NOATIME_FL       (0x00000080)    /* do not update atime */
+#define OCFS2_DIRSYNC_FL       (0x00010000)    /* dirsync behaviour (directories only) */
+
+#define OCFS2_FL_VISIBLE       (0x000100FF)    /* User visible flags */
+#define OCFS2_FL_MODIFIABLE    (0x000100FF)    /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define OCFS2_IOC_GETFLAGS     _IOR('f', 1, long)
+#define OCFS2_IOC_SETFLAGS     _IOW('f', 2, long)
+
 /*
  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
  */
@@ -399,7 +419,9 @@ struct ocfs2_dinode {
        __le32 i_atime_nsec;
        __le32 i_ctime_nsec;
        __le32 i_mtime_nsec;
-/*70*/ __le64 i_reserved1[9];
+       __le32 i_attr;
+       __le32 i_reserved1;
+/*70*/ __le64 i_reserved2[8];
 /*B8*/ union {
                __le64 i_pad1;          /* Generic way to refer to this
                                           64bit union */