Skip to content

Commit

Permalink
ocfs2: add ext2 attributes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Herbert Poetzl authored and Mark Fasheh committed Sep 20, 2006
1 parent b4c98f6 commit ca4d147
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 6 deletions.
1 change: 1 addition & 0 deletions fs/ocfs2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ocfs2-objs := \
file.o \
heartbeat.o \
inode.o \
ioctl.o \
journal.o \
localalloc.o \
mmap.o \
Expand Down
9 changes: 7 additions & 2 deletions fs/ocfs2/dlmglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
5 changes: 3 additions & 2 deletions fs/ocfs2/dlmglue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions fs/ocfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
};
28 changes: 27 additions & 1 deletion fs/ocfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions fs/ocfs2/inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
134 changes: 134 additions & 0 deletions fs/ocfs2/ioctl.c
Original file line number Diff line number Diff line change
@@ -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;
}
}

16 changes: 16 additions & 0 deletions fs/ocfs2/ioctl.h
Original file line number Diff line number Diff line change
@@ -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 */
24 changes: 23 additions & 1 deletion fs/ocfs2/ocfs2_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@
#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)
*/
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit ca4d147

Please sign in to comment.