diff -NurpP linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/Makefile linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/Makefile --- linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/Makefile 2006-01-18 06:08:34 +0100 +++ linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/Makefile 2006-06-09 17:08:32 +0200 @@ -16,6 +16,7 @@ ocfs2-objs := \ file.o \ heartbeat.o \ inode.o \ + ioctl.o \ journal.o \ localalloc.o \ mmap.o \ diff -NurpP linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/file.c linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/file.c --- linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/file.c 2006-03-20 17:33:12 +0100 +++ linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/file.c 2006-06-09 17:53:47 +0200 @@ -1162,9 +1162,12 @@ bail: return ret; } +extern int ocfs2_sync_flags(struct inode *); + struct inode_operations ocfs2_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, + .sync_flags = ocfs2_sync_flags, }; struct inode_operations ocfs2_special_file_iops = { @@ -1172,6 +1175,9 @@ struct inode_operations ocfs2_special_fi .getattr = ocfs2_getattr, }; +extern int ocfs2_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); + struct file_operations ocfs2_fops = { .read = do_sync_read, .write = do_sync_write, @@ -1182,10 +1188,12 @@ struct file_operations ocfs2_fops = { .open = ocfs2_file_open, .aio_read = ocfs2_file_aio_read, .aio_write = ocfs2_file_aio_write, + .ioctl = ocfs2_ioctl, }; struct file_operations ocfs2_dops = { .read = generic_read_dir, .readdir = ocfs2_readdir, .fsync = ocfs2_sync_file, + .ioctl = ocfs2_ioctl, }; diff -NurpP linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/inode.c linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/inode.c --- linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/inode.c 2006-03-20 17:33:12 +0100 +++ linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/inode.c 2006-06-10 03:45:48 +0200 @@ -71,6 +71,81 @@ static int ocfs2_truncate_for_delete(str struct inode *inode, struct buffer_head *fe_bh); +void ocfs2_set_inode_flags(struct inode *inode) +{ + unsigned int flags = OCFS2_I(inode)->ip_flags; + + inode->i_flags &= ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + if (flags & OCFS2_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & OCFS2_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & OCFS2_BARRIER_FL) + inode->i_flags |= S_BARRIER; + + 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; +} + +int ocfs2_sync_flags(struct inode *inode) +{ + unsigned int oldflags, newflags; + + oldflags = OCFS2_I(inode)->ip_flags; + newflags = oldflags & ~(OCFS2_APPEND_FL | + OCFS2_IMMUTABLE_FL | OCFS2_IUNLINK_FL | + OCFS2_BARRIER_FL | OCFS2_NOATIME_FL | + OCFS2_SYNC_FL | OCFS2_DIRSYNC_FL); + + if (IS_APPEND(inode)) + newflags |= OCFS2_APPEND_FL; + if (IS_IMMUTABLE(inode)) + newflags |= OCFS2_IMMUTABLE_FL; + if (IS_IUNLINK(inode)) + newflags |= OCFS2_IUNLINK_FL; + if (IS_BARRIER(inode)) + newflags |= OCFS2_BARRIER_FL; + + /* we do not want to copy superblock flags */ + if (inode->i_flags & S_NOATIME) + newflags |= OCFS2_NOATIME_FL; + if (inode->i_flags & S_SYNC) + newflags |= OCFS2_SYNC_FL; + if (inode->i_flags & S_DIRSYNC) + newflags |= OCFS2_DIRSYNC_FL; + + if (oldflags ^ newflags) { + OCFS2_I(inode)->ip_flags = newflags; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + } + return 0; +} + +static inline void ocfs2_map_dinode(struct inode *inode, struct ocfs2_dinode *fe, int from) +{ + unsigned flags; + + if (from) { + flags = le32_to_cpu(fe->i_flags) & OCFS2_FL_MASK; + OCFS2_I(inode)->ip_flags &= ~OCFS2_FL_MASK; + OCFS2_I(inode)->ip_flags |= flags; + } else { + flags = OCFS2_I(inode)->ip_flags & OCFS2_FL_MASK; + flags |= le32_to_cpu(fe->i_flags) & ~OCFS2_FL_MASK; + fe->i_flags = cpu_to_le32(flags); + } +} + + struct inode *ocfs2_ilookup_for_vote(struct ocfs2_super *osb, u64 blkno, int delete_vote) @@ -265,6 +340,7 @@ int ocfs2_populate_inode(struct inode *i inode->i_mtime.tv_nsec = le32_to_cpu(fe->i_mtime_nsec); inode->i_ctime.tv_sec = le64_to_cpu(fe->i_ctime); inode->i_ctime.tv_nsec = le32_to_cpu(fe->i_ctime_nsec); + ocfs2_map_dinode(inode, fe, 1); if (OCFS2_I(inode)->ip_blkno != le64_to_cpu(fe->i_blkno)) mlog(ML_ERROR, @@ -327,6 +403,7 @@ int ocfs2_populate_inode(struct inode *i ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres, OCFS2_LOCK_TYPE_DATA, inode); + ocfs2_set_inode_flags(inode); status = 0; bail: mlog_exit(status); @@ -1138,6 +1214,7 @@ int ocfs2_mark_inode_dirty(struct ocfs2_ fe->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); fe->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec); fe->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); + ocfs2_map_dinode(inode, fe, 0); status = ocfs2_journal_dirty(handle, bh); if (status < 0) @@ -1179,6 +1256,7 @@ void ocfs2_refresh_inode(struct inode *i inode->i_mtime.tv_nsec = le32_to_cpu(fe->i_mtime_nsec); inode->i_ctime.tv_sec = le64_to_cpu(fe->i_ctime); inode->i_ctime.tv_nsec = le32_to_cpu(fe->i_ctime_nsec); + ocfs2_map_dinode(inode, fe, 1); spin_unlock(&OCFS2_I(inode)->ip_lock); } diff -NurpP linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/ioctl.c linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/ioctl.c --- linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/ioctl.c 1970-01-01 01:00:00 +0100 +++ linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/ioctl.c 2006-06-10 03:44:57 +0200 @@ -0,0 +1,140 @@ +/* + * linux/fs/ocfs2/ioctl.c + * + * Copyright (C) 2006 Herbert Poetzl + * adapted from Remy Card's ext2/ioctl.c + */ + +#include +#include + +#define MLOG_MASK_PREFIX ML_INODE +#include + +#include "ocfs2.h" +#include "alloc.h" +#include "dlmglue.h" +#include "inode.h" +#include "journal.h" + +#include "ocfs2_fs.h" +#include + +static struct { + long ocfs2_flag; + long ext2_flag; +} ocfs2_map[] = { + {OCFS2_NOATIME_FL, EXT2_NOATIME_FL}, + {OCFS2_DIRSYNC_FL, EXT2_DIRSYNC_FL}, + {OCFS2_SYNC_FL, EXT2_SYNC_FL}, + {OCFS2_SECRM_FL, EXT2_SECRM_FL}, + {OCFS2_UNRM_FL, EXT2_UNRM_FL}, + {OCFS2_APPEND_FL, EXT2_APPEND_FL}, + {OCFS2_IMMUTABLE_FL, EXT2_IMMUTABLE_FL}, + {0, 0}, +}; + +static long ocfs2_map_ext2(unsigned long flags, int from) +{ + int index=0; + long mapped=0; + + while (ocfs2_map[index].ocfs2_flag) { + if (from) { + if (ocfs2_map[index].ext2_flag & flags) + mapped |= ocfs2_map[index].ocfs2_flag; + } else { + if (ocfs2_map[index].ocfs2_flag & flags) + mapped |= ocfs2_map[index].ext2_flag; + } + index++; + } + return mapped; +} + +extern void ocfs2_set_inode_flags(struct inode *); + + +int ocfs2_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + 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 int flags; + int status; + + switch (cmd) { + case OCFS2_IOC_GETFLAGS: + flags = ocfs2_inode->ip_flags & OCFS2_FL_VISIBLE; + flags = ocfs2_map_ext2(flags, 0); + return put_user(flags, (int __user *) arg); + case OCFS2_IOC_SETFLAGS: { + unsigned int oldflags; + + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + flags = ocfs2_map_ext2(flags, 1); + if (!S_ISDIR(inode->i_mode)) + flags &= ~OCFS2_DIRSYNC_FL; + + status = ocfs2_meta_lock(inode, NULL, &bh, 1); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + 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_flags; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + */ + if ((oldflags & OCFS2_IMMUTABLE_FL) || + ((flags ^ oldflags) & (OCFS2_APPEND_FL | + OCFS2_IMMUTABLE_FL | OCFS2_IUNLINK_FL))) { + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } + + flags = flags & OCFS2_FL_MODIFIABLE; + flags |= oldflags & ~OCFS2_FL_MODIFIABLE; + ocfs2_inode->ip_flags = 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: + if (bh) + brelse(bh); + + mlog_exit(status); + return 0; + } + default: + return -ENOTTY; + } +} + diff -NurpP linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/ocfs2_fs.h linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/ocfs2_fs.h --- linux-2.6.16.20-vs2.1.1-rc22/fs/ocfs2/ocfs2_fs.h 2006-04-09 13:49:54 +0200 +++ linux-2.6.16.20-vs2.1.1-rc22.2.1/fs/ocfs2/ocfs2_fs.h 2006-06-10 03:43:48 +0200 @@ -114,6 +114,26 @@ #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */ #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */ +#define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */ +#define OCFS2_SYNC_FL (0x00020000) /* Synchronous updates */ +#define OCFS2_SECRM_FL (0x00040000) /* Secure deletion */ +#define OCFS2_UNRM_FL (0x00080000) /* Undelete */ + +#define OCFS2_IMMUTABLE_FL (0x00100000) /* Immutable file */ +#define OCFS2_APPEND_FL (0x00200000) /* writes to file may only append */ +#define OCFS2_NOATIME_FL (0x00400000) /* do not update atime */ + +#define OCFS2_BARRIER_FL (0x04000000) /* Barrier for chroot() */ +#define OCFS2_IUNLINK_FL (0x08000000) /* Immutable unlink */ + +#define OCFS2_FL_MASK (0x0FFF0000) +#define OCFS2_FL_VISIBLE (0x00FF0000) +#define OCFS2_FL_MODIFIABLE (0x007F0000) +#define OCFS2_FL_INHERIT (0x007C0000) + +#define OCFS2_IOC_GETFLAGS _IOR('f', 1, long) +#define OCFS2_IOC_SETFLAGS _IOW('f', 2, long) + /* * Journal Flags (ocfs2_dinode.id1.journal1.i_flags) */