Received: with ECARTIS (v1.0.0; list linux-xfs); Sat, 16 Aug 2003 22:02:40 -0700 (PDT) Received: from hob.acsalaska.net (hob.acsalaska.net [209.112.155.42]) by oss.sgi.com (8.12.9/8.12.9) with SMTP id h7H52IFl012795 for ; Sat, 16 Aug 2003 22:02:19 -0700 Received: from erbenson.alaska.net (74-pm2.nwc.alaska.net [209.112.138.74]) by hob.acsalaska.net (8.12.9/8.12.9) with ESMTP id h7H525dK018273 for ; Sat, 16 Aug 2003 21:02:05 -0800 (AKDT) (envelope-from erbenson@alaska.net) Received: from plato.local.lan (plato.local.lan [192.168.0.4]) by erbenson.alaska.net (Postfix) with ESMTP id 55B363A04 for ; Sat, 16 Aug 2003 21:02:02 -0800 (AKDT) Received: by plato.local.lan (Postfix, from userid 1000) id 6B34D40FF44; Sat, 16 Aug 2003 21:02:03 -0800 (AKDT) Date: Sat, 16 Aug 2003 21:02:03 -0800 From: Ethan Benson To: linux-xfs@oss.sgi.com Subject: [PATCH] Implement immutable/append-only flags in XFS #5 Message-ID: <20030817050203.GA11982@plato.local.lan> Mail-Followup-To: linux-xfs@oss.sgi.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="azLHFNyN32YCQGCU" Content-Disposition: inline User-Agent: Mutt/1.3.28i X-OS: Debian GNU X-gpg-fingerprint: E3E4 D0BC 31BC F7BB C1DD C3D6 24AC 7B1A 2C44 7AFC X-gpg-key: http://www.alaska.net/~erbenson/gpg/key.asc Mail-Copies-To: nobody X-No-CC: I subscribe to this list; do not CC me on replies. X-ACS-Spam-Status: no X-Scanned-By: MIMEDefang 2.35 X-archive-position: 66 X-ecartis-version: Ecartis v1.0.0 Sender: linux-xfs-bounce@oss.sgi.com Errors-to: linux-xfs-bounce@oss.sgi.com X-original-sender: erbenson@alaska.net Precedence: bulk X-list: linux-xfs Content-Length: 24347 Lines: 630 --azLHFNyN32YCQGCU Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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/ --azLHFNyN32YCQGCU Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="xfs-xflags.diff" 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 #include @@ -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); --azLHFNyN32YCQGCU Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="open.c.diff" --- 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; --azLHFNyN32YCQGCU--