[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Implement immutable/append-only flags in XFS #5
Hi,
[fifth revision: only changes is to update to current 2.4.21 CVS]
Over time there has been many requests for ext2 file flags such as
immutable, append-only, sync, noatime be implemented in XFS.
So, here it is. I have implemented all of the above flags in 2.4.21
CVS. The patch is relatively small and non-invasive, and from my
testing appears to cause no backwards compatibility issues (older
kernels ignore, and leave alone the new flags). Also xfs_repair and
xfs_check do not seem to have any problems with the new flags either.
If any XFS users would like to try this patch and report on it please
do. My testing indicates its stable and will cause no problems except
as discussed below with xfsdump.
However during my testing I did discover 3 issues:
1: The Linux VFS contains a bug which allows timestamp modification of
immutable/append-only files. I have fixed this issue, and will send
the patch to the linux-kernel mailing list shortly. I have included
that patch in this mail for completeness.
2: xfsrestore breaks when immutable or append-only files are included
in the dump. The problem is xfsrestore restores the file inode flags
too soon, and then loses the access it needs to restore extended
attributes, uid, gid, and permissions. I am not familiar enough with
xfsrestore to really propose the fix, however i believe just changing
it to restore at the very least immutable/append-only flags very last
after all other restoration is complete should suffice to solve this
problem.
3: I just found an undocumented behavior with regards to ext2's file
flags; when set on a directory any new file/dir created will inherit
the flags of the parent directory. I am not entirely convinced this
is a good idea, at least for *all* flags. In ext2 this behavior has
been half broken for as near as i can tell, forever up to 2.4.20
(2.4.21 fixes it), the brokenness is that the vfs is not immediately
informed of any of the flags except sync, thus they don't actually go
into affect on new files until the inode is revalidated (which could
take quite some time). In addition ext2 only refrains from doing this
on symlinks, not device special files; this means if you create a
device node in a append-only directory the only way you will ever be
able to remove it is with debugfs. (ioctl() calls on a device file go
to the driver handling the node, not to the filesystem holding the
node, thus chattr won't help you).
My question on #3 is whether we want this behavior in XFS? my current
patch implements it only for the sync bit, and only to regular files
and directories. My opinion is that the only flag this really makes
sense for is sync, since setting the sync flag on a directory does not
actually do anything for you (it only affects files), so making all
new files created under a sync directory is seemingly sensible (and
probably what the user would expect, more or less). this might make
sense for noatime too, but I am less convinced of this. I am
definitely not convinced its a sensible idea for append-only since it
ends up allowing non-privileged users to create append-only files,
which is not normally permitted. Also automatically setting the
append-only flag on a newly created file won't necessarily make it
append-only immediately, since a caller doing
open("append-only-dir/file" O_RDWR|O_CREAT) will retain full
read/write access so long as the file descriptor is kept open (the
same is true if you chmod() a file, open descriptors retain access
even if they could not get it on a new open()).
So for now I submit the patch without the ext2 inheritance behavior
(except for sync to IFREG and IFDIR), if you believe we should
implement the ext2 behavior either partially, or fully I should be
able to do that.
I have also implemented the EXT2_IOC_SETFLAGS/EXT2_IOC_GETFLAGS
ioctl()s so chattr/lsattr will work on xfs, this part of the patch is
optional, if excluded then either lsattr/chattr would need to be
modified to use XFS_IOC_FSSETXATTR and XFS_IOC_FSGETXATTR ioctls.
I have a (somewhat hideous) test program to check as many things as i
could think of to ensure immutable/append-only are properly enforced,
the only thing lacking in it is tests of all the XFS ioctls, perhaps
someone familiar with xfs ioctls could add these, currently the
libhandle open/write tests are done. You can find this test program
at http://penguinppc.org/~eb/t_immutable.c
Important: this test program creates a test area with full world
read/write permissions to ensure regular file permissions are not
tainting the test, therefore it is NOT SAFE to run on systems with
untrusted users. the usage is t_immutable -c /some/dir which will
create a test area as /some/dir and run tests in it. t_immutable -C
will create the test area without running any tests, and t_immutable
-r will remove a test area. t_immutable /some/dir will run the tests
on a previously created test area.
Note if you run t_immutable on an ext2 filesystem in 2.4.21 kernels
you will need to use debugfs to get rid of the device node it creates
(same on kernels prior to 2.4.21 if you leave the test area around
long enough). see above for why.
Also note that there is currently a bug in the XFS handle code, if you
run my test program, then use it to delete the test-area you will get
minor filesystem corruption on umount.
feedback is welcome.
diffstat output follows:
linux/xfs_ext2_ioctl.h | 45 ++++++++++++++++++++++
linux/xfs_ioctl.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++
linux/xfs_iops.c | 6 ++
linux/xfs_super.c | 16 +++++++
linux/xfs_vnode.c | 17 ++++++++
xfs_acl.c | 2
xfs_cap.c | 2
xfs_dinode.h | 24 ++++++++---
xfs_fs.h | 7 ++-
xfs_inode.c | 7 ++-
xfs_itable.c | 8 +++
xfs_vnodeops.c | 16 +++++++
12 files changed, 241 insertions(+), 9 deletions(-)
--
Ethan Benson
http://www.alaska.net/~erbenson/
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ext2_ioctl.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_ext2_ioctl.h
--- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ext2_ioctl.h Wed Dec 31 14:00:00 1969
+++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_ext2_ioctl.h Mon Jul 21 15:57:33 2003
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_EXT2_IOCTL_H__
+#define __XFS_EXT2_IOCTL_H__
+
+/* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support
+ * chattr/lsattr */
+#define XFS_IOC_EXT2_GETFLAGS _IOR('f', 1, long)
+#define XFS_IOC_EXT2_SETFLAGS _IOW('f', 2, long)
+
+#define EXT2_FLAG_SYNC 0x00000008 /* Synchronous updates */
+#define EXT2_FLAG_IMMUTABLE 0x00000010 /* Immutable file */
+#define EXT2_FLAG_APPEND 0x00000020 /* writes to file may only append */
+#define EXT2_FLAG_NOATIME 0x00000080 /* do not update atime */
+
+#endif /* __XFS_EXT2_IOCTL_H__ */
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ioctl.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c
--- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ioctl.c Mon Jul 21 15:12:50 2003
+++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c Mon Jul 21 15:19:13 2003
@@ -66,6 +66,7 @@
#include "xfs_utils.h"
#include "xfs_dfrag.h"
#include "xfs_fsops.h"
+#include "xfs_ext2_ioctl.h"
#include <linux/dcache.h>
#include <linux/iobuf.h>
@@ -327,6 +328,13 @@
if (permflag & O_TRUNC)
permflag |= 2;
+ if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
+ (permflag & FMODE_WRITE) && IS_APPEND(inode))
+ return -XFS_ERROR(EPERM);
+
+ if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode))
+ return -XFS_ERROR(EACCES);
+
/* Can't write directories. */
if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
iput(inode);
@@ -447,6 +455,9 @@
if (error)
return -error;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -XFS_ERROR(EPERM);
+
if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
VN_RELE(vp);
return -XFS_ERROR(EFAULT);
@@ -532,11 +543,21 @@
NULL, ops[i].am_error);
break;
case ATTR_OP_SET:
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ kfree(ops);
+ VN_RELE(vp);
+ return -XFS_ERROR(EPERM);
+ }
VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
ops[i].am_length, ops[i].am_flags,
NULL, ops[i].am_error);
break;
case ATTR_OP_REMOVE:
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ kfree(ops);
+ VN_RELE(vp);
+ return -XFS_ERROR(EPERM);
+ }
VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
NULL, ops[i].am_error);
break;
@@ -842,6 +863,75 @@
error = xfs_errortag_clearall(mp);
return -error;
+ case XFS_IOC_EXT2_GETFLAGS: {
+ unsigned int flags = 0;
+
+ if (vp->v_inode.i_flags & S_IMMUTABLE)
+ flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */
+ if (vp->v_inode.i_flags & S_APPEND)
+ flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */
+ if (vp->v_inode.i_flags & S_SYNC)
+ flags |= EXT2_FLAG_SYNC; /* EXT2_SYNC_FL */
+ if (vp->v_inode.i_flags & S_NOATIME)
+ flags |= EXT2_FLAG_NOATIME; /* EXT2_NOATIME_FL */
+
+ if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_EXT2_SETFLAGS: {
+ vattr_t va;
+ unsigned int flags;
+ int attr_flags = 0;
+
+ if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags)))
+ return -XFS_ERROR(EFAULT);
+
+ /* we need to do getattr to preserve XFS xflags ext2
+ * has no knowledge of */
+
+ va.va_mask = XFS_AT_XFLAGS;
+ VOP_GETATTR(vp, &va, 0, NULL, error);
+ if (error)
+ return -error;
+
+ if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) ||
+ va.va_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND))
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -XFS_ERROR(EPERM);
+
+ /* don't silently ignore unsupported ext2 flags */
+ if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND|
+ EXT2_FLAG_SYNC|EXT2_FLAG_NOATIME))
+ return -XFS_ERROR(EOPNOTSUPP);
+
+ if (flags & EXT2_FLAG_IMMUTABLE) /* EXT2_IMMUTABLE_FL */
+ va.va_xflags |= XFS_XFLAG_IMMUTABLE;
+ else
+ va.va_xflags &= ~XFS_XFLAG_IMMUTABLE;
+ if (flags & EXT2_FLAG_APPEND) /* EXT2_APPEND_FL */
+ va.va_xflags |= XFS_XFLAG_APPEND;
+ else
+ va.va_xflags &= ~XFS_XFLAG_APPEND;
+ if (flags & EXT2_FLAG_SYNC) /* EXT2_SYNC_FL */
+ va.va_xflags |= XFS_XFLAG_SYNC;
+ else
+ va.va_xflags &= ~XFS_XFLAG_SYNC;
+ if (flags & EXT2_FLAG_NOATIME) /* EXT2_NOATIME_FL */
+ va.va_xflags |= XFS_XFLAG_NOATIME;
+ else
+ va.va_xflags &= ~XFS_XFLAG_NOATIME;
+
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
+ attr_flags |= ATTR_NONBLOCK;
+
+ VOP_SETATTR(vp, &va, attr_flags, NULL, error);
+ if (!error)
+ vn_revalidate(vp); /* push immutable/append flags into vfs inode */
+ return -error;
+ }
+
default:
return -ENOTTY;
}
@@ -859,6 +949,9 @@
int attr_flags = 0;
int error;
+ if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
+ return -XFS_ERROR(EPERM);
+
if (filp->f_flags & O_RDONLY)
return -XFS_ERROR(EBADF);
@@ -1012,6 +1105,11 @@
if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa)))
return -XFS_ERROR(EFAULT);
+ if (fa.fsx_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND) ||
+ va.va_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND))
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -XFS_ERROR(EPERM);
+
va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
va.va_xflags = fa.fsx_xflags;
va.va_extsize = fa.fsx_extsize;
@@ -1020,6 +1118,8 @@
attr_flags |= ATTR_NONBLOCK;
VOP_SETATTR(vp, &va, attr_flags, NULL, error);
+ if (!error)
+ vn_revalidate(vp); /* push immutable/append flags into vfs inode */
return -error;
}
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_iops.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c
--- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_iops.c Sat Aug 16 19:01:10 2003
+++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c Sat Aug 16 20:21:46 2003
@@ -633,6 +633,9 @@
return error;
}
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -EPERM;
+
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
xflags |= ATTR_CREATE;
@@ -782,6 +785,9 @@
error = xfs_cap_vremove(vp);
return error;
}
+
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -EPERM;
if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
xfs_namespaces[ROOT_NAMES].namelen) == 0) {
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_super.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c
--- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_super.c Sat Aug 16 19:01:10 2003
+++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c Sat Aug 16 20:21:49 2003
@@ -181,6 +181,22 @@
inode->i_atime = ip->i_d.di_atime.t_sec;
inode->i_mtime = ip->i_d.di_mtime.t_sec;
inode->i_ctime = ip->i_d.di_ctime.t_sec;
+ if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
+ inode->i_flags |= S_IMMUTABLE;
+ else
+ inode->i_flags &= ~S_IMMUTABLE;
+ if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
+ inode->i_flags |= S_APPEND;
+ else
+ inode->i_flags &= ~S_APPEND;
+ if (ip->i_d.di_flags & XFS_DIFLAG_SYNC)
+ inode->i_flags |= S_SYNC;
+ else
+ inode->i_flags &= ~S_SYNC;
+ if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME)
+ inode->i_flags |= S_NOATIME;
+ else
+ inode->i_flags &= ~S_NOATIME;
vp->v_flag &= ~VMODIFIED;
}
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_vnode.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c
--- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_vnode.c Mon Jul 21 15:13:07 2003
+++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c Mon Jul 21 15:19:13 2003
@@ -224,6 +224,23 @@
inode->i_mtime = va.va_mtime.tv_sec;
inode->i_ctime = va.va_ctime.tv_sec;
inode->i_atime = va.va_atime.tv_sec;
+ if (va.va_xflags & XFS_XFLAG_IMMUTABLE)
+ inode->i_flags |= S_IMMUTABLE;
+ else
+ inode->i_flags &= ~S_IMMUTABLE;
+ if (va.va_xflags & XFS_XFLAG_APPEND)
+ inode->i_flags |= S_APPEND;
+ else
+ inode->i_flags &= ~S_APPEND;
+ if (va.va_xflags & XFS_XFLAG_SYNC)
+ inode->i_flags |= S_SYNC;
+ else
+ inode->i_flags &= ~S_SYNC;
+ if (va.va_xflags & XFS_XFLAG_NOATIME)
+ inode->i_flags |= S_NOATIME;
+ else
+ inode->i_flags &= ~S_NOATIME;
+
VUNMODIFY(vp);
}
return -error;
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_acl.c linux-2.4-xfs/linux/fs/xfs/xfs_acl.c
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_acl.c Mon Jul 21 15:06:54 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_acl.c Mon Jul 21 15:19:13 2003
@@ -388,6 +388,8 @@
vattr_t va;
int error;
+ if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
+ return EPERM;
if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR)
return ENOTDIR;
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_cap.c linux-2.4-xfs/linux/fs/xfs/xfs_cap.c
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_cap.c Mon Jul 21 15:08:15 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_cap.c Mon Jul 21 15:19:13 2003
@@ -192,6 +192,8 @@
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return EROFS;
+ if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
+ return EPERM;
if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
return error;
va.va_mask = XFS_AT_UID;
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_dinode.h linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_dinode.h Sat Aug 16 19:00:58 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h Sat Aug 16 20:21:09 2003
@@ -471,13 +471,23 @@
* There should be a one-to-one correspondence between these flags and the
* XFS_XFLAG_s.
*/
-#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */
-#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */
-#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */
-#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
-#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
-#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
+#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */
+#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */
+#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */
+#define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */
+#define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */
+#define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */
+#define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */
+#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
+#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
+#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
+#define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT)
+#define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT)
+#define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT)
+#define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT)
#define XFS_DIFLAG_ALL \
- (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM)
+ (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM| \
+ XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND|XFS_DIFLAG_SYNC| \
+ XFS_DIFLAG_NOATIME)
#endif /* __XFS_DINODE_H__ */
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_fs.h linux-2.4-xfs/linux/fs/xfs/xfs_fs.h
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_fs.h Mon Jul 21 15:09:27 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_fs.h Mon Jul 21 15:19:13 2003
@@ -71,9 +71,14 @@
*/
#define XFS_XFLAG_REALTIME 0x00000001
#define XFS_XFLAG_PREALLOC 0x00000002
+#define XFS_XFLAG_IMMUTABLE 0x00000008
+#define XFS_XFLAG_APPEND 0x00000010
+#define XFS_XFLAG_SYNC 0x00000020
+#define XFS_XFLAG_NOATIME 0x00000040
#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
#define XFS_XFLAG_ALL \
- ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR )
+ ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_IMMUTABLE| \
+ XFS_XFLAG_APPEND|XFS_XFLAG_SYNC|XFS_XFLAG_NOATIME|XFS_XFLAG_HASATTR )
/*
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_inode.c linux-2.4-xfs/linux/fs/xfs/xfs_inode.c
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_inode.c Sat Aug 16 19:00:58 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_inode.c Sat Aug 16 20:21:21 2003
@@ -1210,6 +1210,8 @@
break;
case IFREG:
case IFDIR:
+ if (pip->i_d.di_flags & XFS_DIFLAG_SYNC)
+ ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
case IFLNK:
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_df.if_flags = XFS_IFEXTENTS;
@@ -3500,6 +3502,9 @@
if (IS_RDONLY(inode) &&
(S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode)))
return XFS_ERROR(EROFS);
+
+ if (IS_IMMUTABLE(inode))
+ return XFS_ERROR(EACCES);
}
/*
@@ -3623,7 +3628,7 @@
* Don't update access timestamps on reads if mounted "noatime"
* Throw it away if anyone asks us.
*/
- if (ip->i_mount->m_flags & XFS_MOUNT_NOATIME &&
+ if ((ip->i_mount->m_flags & XFS_MOUNT_NOATIME || IS_NOATIME(inode)) &&
((flags & (XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD|XFS_ICHGTIME_CHG))
== XFS_ICHGTIME_ACC))
return;
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_itable.c linux-2.4-xfs/linux/fs/xfs/xfs_itable.c
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_itable.c Mon Jul 21 15:10:06 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_itable.c Mon Jul 21 15:19:13 2003
@@ -163,6 +163,14 @@
XFS_XFLAG_REALTIME : 0) |
((di_flags & XFS_DIFLAG_PREALLOC) ?
XFS_XFLAG_PREALLOC : 0) |
+ ((di_flags & XFS_DIFLAG_IMMUTABLE) ?
+ XFS_XFLAG_IMMUTABLE : 0) |
+ ((di_flags & XFS_DIFLAG_APPEND) ?
+ XFS_XFLAG_APPEND : 0) |
+ ((di_flags & XFS_DIFLAG_SYNC) ?
+ XFS_XFLAG_SYNC : 0) |
+ ((di_flags & XFS_DIFLAG_NOATIME) ?
+ XFS_XFLAG_NOATIME : 0) |
(XFS_CFORK_Q_ARCH(dic, arch) ?
XFS_XFLAG_HASATTR : 0);
diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_vnodeops.c linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c
--- linux-2.4-xfs.orig/linux/fs/xfs/xfs_vnodeops.c Sat Aug 16 19:00:58 2003
+++ linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c Sat Aug 16 20:21:35 2003
@@ -266,6 +266,14 @@
XFS_XFLAG_REALTIME : 0) |
((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ?
XFS_XFLAG_PREALLOC : 0) |
+ ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) ?
+ XFS_XFLAG_IMMUTABLE : 0) |
+ ((ip->i_d.di_flags & XFS_DIFLAG_APPEND) ?
+ XFS_XFLAG_APPEND : 0) |
+ ((ip->i_d.di_flags & XFS_DIFLAG_SYNC) ?
+ XFS_XFLAG_SYNC : 0) |
+ ((ip->i_d.di_flags & XFS_DIFLAG_NOATIME) ?
+ XFS_XFLAG_NOATIME : 0) |
(XFS_IFORK_Q(ip) ?
XFS_XFLAG_HASATTR : 0);
vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog;
@@ -833,6 +841,14 @@
ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
ip->i_iocore.io_flags |= XFS_IOCORE_RT;
}
+ if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
+ ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE;
+ if (vap->va_xflags & XFS_XFLAG_APPEND)
+ ip->i_d.di_flags |= XFS_DIFLAG_APPEND;
+ if (vap->va_xflags & XFS_XFLAG_SYNC)
+ ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+ if (vap->va_xflags & XFS_XFLAG_NOATIME)
+ ip->i_d.di_flags |= XFS_DIFLAG_NOATIME;
/* can't set PREALLOC this way, just ignore it */
}
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
--- linux.orig/fs/open.c Sun Jun 1 20:39:38 2003
+++ linux/fs/open.c Sun Jun 1 20:54:14 2003
@@ -272,6 +272,9 @@
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
+ error = -EPERM;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto dput_and_out;
error = get_user(newattrs.ia_atime, ×->actime);
if (!error)
error = get_user(newattrs.ia_mtime, ×->modtime);
@@ -280,6 +283,9 @@
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
+ error = -EACCES;
+ if (IS_IMMUTABLE(inode))
+ goto dput_and_out;
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;
@@ -318,6 +324,9 @@
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (utimes) {
struct timeval times[2];
+ error = -EPERM;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto dput_and_out;
error = -EFAULT;
if (copy_from_user(×, utimes, sizeof(times)))
goto dput_and_out;
@@ -325,6 +334,10 @@
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
+ error = -EACCES;
+ if (IS_IMMUTABLE(inode))
+ goto dput_and_out;
+
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;