From 57b6451fa810650ad69e7a032d4b3f68dd08ad95 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 15 Sep 2003 02:39:24 -0500 Subject: [PATCH] [XFS] Implement several additional inode flags - immutable, append-only, etc; contributed by Ethan Benson. SGI Modid: 2.5.x-xfs:slinx:158362a --- fs/xfs/linux/xfs_globals.c | 2 + fs/xfs/linux/xfs_ioctl.c | 142 ++++++++++++++++++++++++++++++++++--- fs/xfs/linux/xfs_iops.c | 6 ++ fs/xfs/linux/xfs_linux.h | 2 + fs/xfs/linux/xfs_super.c | 17 ++++- fs/xfs/linux/xfs_sysctl.c | 10 +++ fs/xfs/linux/xfs_sysctl.h | 18 +++-- fs/xfs/linux/xfs_vnode.c | 16 +++++ fs/xfs/xfs_acl.c | 2 + fs/xfs/xfs_cap.c | 2 + fs/xfs/xfs_dinode.h | 24 ++++--- fs/xfs/xfs_fs.h | 12 ++-- fs/xfs/xfs_ialloc.c | 2 +- fs/xfs/xfs_inode.c | 9 ++- fs/xfs/xfs_itable.c | 12 +++- fs/xfs/xfs_vnodeops.c | 38 +++++++++- fs/xfs/xfsidbg.c | 6 ++ 17 files changed, 286 insertions(+), 34 deletions(-) diff --git a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c index 2509bfbe06b4c..ef99bdf05ff12 100644 --- a/fs/xfs/linux/xfs_globals.c +++ b/fs/xfs/linux/xfs_globals.c @@ -59,6 +59,8 @@ xfs_param_t xfs_params = { .error_level = { 0, 3, 11 }, .sync_interval = { HZ, 30*HZ, 60*HZ }, .stats_clear = { 0, 0, 1 }, + .inherit_sync = { 0, 1, 1 }, + .inherit_nodump = { 0, 1, 1 }, }; /* diff --git a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c index 55691b0879d41..d3860a6f85626 100644 --- a/fs/xfs/linux/xfs_ioctl.c +++ b/fs/xfs/linux/xfs_ioctl.c @@ -72,6 +72,13 @@ #include #include +/* + * ioctl commands that are used by Linux filesystems + */ +#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) +#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) +#define XFS_IOC_GETVERSION _IOR('v', 1, long) + /* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to @@ -328,6 +335,17 @@ xfs_open_by_handle( if (permflag & O_TRUNC) permflag |= 2; + if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && + (permflag & FMODE_WRITE) && IS_APPEND(inode)) { + iput(inode); + return -XFS_ERROR(EPERM); + } + + if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) { + iput(inode); + return -XFS_ERROR(EACCES); + } + /* Can't write directories. */ if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { iput(inode); @@ -429,6 +447,11 @@ xfs_fssetdm_by_handle( if (error) return -error; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + VN_RELE(vp); + return -XFS_ERROR(EPERM); + } + if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { VN_RELE(vp); return -XFS_ERROR(EFAULT); @@ -514,11 +537,19 @@ xfs_attrmulti_by_handle( NULL, ops[i].am_error); break; case ATTR_OP_SET: + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + ops[i].am_error = EPERM; + break; + } 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)) { + ops[i].am_error = EPERM; + break; + } VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags, NULL, ops[i].am_error); break; @@ -566,6 +597,7 @@ xfs_ioc_fsgeometry( STATIC int xfs_ioc_xattr( vnode_t *vp, + xfs_inode_t *ip, struct file *filp, unsigned int cmd, unsigned long arg); @@ -648,10 +680,13 @@ xfs_ioctl( case XFS_IOC_FSGEOMETRY: return xfs_ioc_fsgeometry(mp, arg); + case XFS_IOC_GETVERSION: + case XFS_IOC_GETXFLAGS: + case XFS_IOC_SETXFLAGS: case XFS_IOC_FSGETXATTR: case XFS_IOC_FSSETXATTR: case XFS_IOC_FSGETXATTRA: - return xfs_ioc_xattr(vp, filp, cmd, arg); + return xfs_ioc_xattr(vp, ip, filp, cmd, arg); case XFS_IOC_FSSETDM: { struct fsdmidata dmi; @@ -837,6 +872,9 @@ xfs_ioc_space( 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); @@ -957,9 +995,50 @@ xfs_ioc_fsgeometry( return 0; } +/* + * Linux extended inode flags interface. + */ +#define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */ +#define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */ +#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */ +#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */ +#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */ + +STATIC unsigned int +xfs_merge_ioc_xflags( + unsigned int flags, + unsigned int start) +{ + unsigned int xflags = start; + + if (flags & LINUX_XFLAG_IMMUTABLE) + xflags |= XFS_XFLAG_IMMUTABLE; + else + xflags &= ~XFS_XFLAG_IMMUTABLE; + if (flags & LINUX_XFLAG_APPEND) + xflags |= XFS_XFLAG_APPEND; + else + xflags &= ~XFS_XFLAG_APPEND; + if (flags & LINUX_XFLAG_SYNC) + xflags |= XFS_XFLAG_SYNC; + else + xflags &= ~XFS_XFLAG_SYNC; + if (flags & LINUX_XFLAG_NOATIME) + xflags |= XFS_XFLAG_NOATIME; + else + xflags &= ~XFS_XFLAG_NOATIME; + if (flags & LINUX_XFLAG_NODUMP) + xflags |= XFS_XFLAG_NODUMP; + else + xflags &= ~XFS_XFLAG_NODUMP; + + return xflags; +} + STATIC int xfs_ioc_xattr( vnode_t *vp, + xfs_inode_t *ip, struct file *filp, unsigned int cmd, unsigned long arg) @@ -967,6 +1046,8 @@ xfs_ioc_xattr( struct fsxattr fa; vattr_t va; int error; + int attr_flags; + unsigned int flags; switch (cmd) { case XFS_IOC_FSGETXATTR: { @@ -985,24 +1066,24 @@ xfs_ioc_xattr( } case XFS_IOC_FSSETXATTR: { - int attr_flags = 0; - if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) return -XFS_ERROR(EFAULT); + attr_flags = 0; + if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + attr_flags |= ATTR_NONBLOCK; + va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; va.va_xflags = fa.fsx_xflags; va.va_extsize = fa.fsx_extsize; - 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); /* update Linux inode flags */ return -error; } case XFS_IOC_FSGETXATTRA: { - va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; VOP_GETATTR(vp, &va, 0, NULL, error); if (error) @@ -1017,9 +1098,54 @@ xfs_ioc_xattr( return 0; } + case XFS_IOC_GETXFLAGS: { + flags = 0; + if (ip->i_d.di_flags & XFS_XFLAG_IMMUTABLE) + flags |= LINUX_XFLAG_IMMUTABLE; + if (ip->i_d.di_flags & XFS_XFLAG_APPEND) + flags |= LINUX_XFLAG_APPEND; + if (ip->i_d.di_flags & XFS_XFLAG_SYNC) + flags |= LINUX_XFLAG_SYNC; + if (ip->i_d.di_flags & XFS_XFLAG_NOATIME) + flags |= LINUX_XFLAG_NOATIME; + if (ip->i_d.di_flags & XFS_XFLAG_NODUMP) + flags |= LINUX_XFLAG_NODUMP; + if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_SETXFLAGS: { + if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags))) + return -XFS_ERROR(EFAULT); + + if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ + LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ + LINUX_XFLAG_SYNC)) + return -XFS_ERROR(EOPNOTSUPP); + + attr_flags = 0; + if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + attr_flags |= ATTR_NONBLOCK; + + va.va_mask = XFS_AT_XFLAGS; + va.va_xflags = xfs_merge_ioc_xflags(flags, ip->i_d.di_flags); + + VOP_SETATTR(vp, &va, attr_flags, NULL, error); + if (!error) + vn_revalidate(vp); /* update Linux inode flags */ + return -error; + } + + case XFS_IOC_GETVERSION: { + flags = LINVFS_GET_IP(vp)->i_generation; + if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) + return -XFS_ERROR(EFAULT); + return 0; + } + default: return -ENOTTY; - } } diff --git a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c index cb9bcdda6d015..11c1736bf4f76 100644 --- a/fs/xfs/linux/xfs_iops.c +++ b/fs/xfs/linux/xfs_iops.c @@ -638,6 +638,9 @@ linvfs_setxattr( 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; @@ -787,6 +790,9 @@ linvfs_removexattr( 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) { if (!capable(CAP_SYS_ADMIN)) diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h index fe259b0c32f11..f319e8368ef5c 100644 --- a/fs/xfs/linux/xfs_linux.h +++ b/fs/xfs/linux/xfs_linux.h @@ -96,6 +96,8 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) #define xfs_error_level xfs_params.error_level.val #define xfs_syncd_interval xfs_params.sync_interval.val #define xfs_stats_clear xfs_params.stats_clear.val +#define xfs_inherit_sync xfs_params.inherit_sync.val +#define xfs_inherit_nodump xfs_params.inherit_nodump.val #define NBPP PAGE_SIZE #define DPPSHFT (PAGE_SHIFT - 9) diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 1bd4b3a4a6045..76ca5aec56d22 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -187,7 +187,22 @@ xfs_revalidate_inode( inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; - + 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 --git a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c index 34041998ba390..1b731f95b1edf 100644 --- a/fs/xfs/linux/xfs_sysctl.c +++ b/fs/xfs/linux/xfs_sysctl.c @@ -97,6 +97,16 @@ STATIC ctl_table xfs_table[] = { &sysctl_intvec, NULL, &xfs_params.sync_interval.min, &xfs_params.sync_interval.max}, + {XFS_INHERIT_SYNC, "inherit_sync", &xfs_params.inherit_sync.val, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, + &xfs_params.inherit_sync.min, &xfs_params.inherit_sync.max}, + + {XFS_INHERIT_NODUMP, "inherit_nodump", &xfs_params.inherit_nodump.val, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, + &xfs_params.inherit_nodump.min, &xfs_params.inherit_nodump.max}, + /* please keep this the last entry */ #ifdef CONFIG_PROC_FS {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, diff --git a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h index 45bc8a0a8f42b..0b6e690172aa6 100644 --- a/fs/xfs/linux/xfs_sysctl.h +++ b/fs/xfs/linux/xfs_sysctl.h @@ -55,6 +55,8 @@ typedef struct xfs_param { xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ xfs_sysctl_val_t sync_interval; /* time between sync calls */ xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ + xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */ + xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */ } xfs_param_t; /* @@ -73,13 +75,15 @@ typedef struct xfs_param { */ enum { - XFS_RESTRICT_CHOWN = 1, - XFS_SGID_INHERIT = 2, - XFS_SYMLINK_MODE = 3, - XFS_PANIC_MASK = 4, - XFS_ERRLEVEL = 5, - XFS_SYNC_INTERVAL = 6, - XFS_STATS_CLEAR = 7, + XFS_RESTRICT_CHOWN = 3, + XFS_SGID_INHERIT = 4, + XFS_SYMLINK_MODE = 5, + XFS_PANIC_MASK = 6, + XFS_ERRLEVEL = 7, + XFS_SYNC_INTERVAL = 8, + XFS_STATS_CLEAR = 12, + XFS_INHERIT_SYNC = 13, + XFS_INHERIT_NODUMP = 14, }; extern xfs_param_t xfs_params; diff --git a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c index fd0d0fca194d6..92a1a488e372d 100644 --- a/fs/xfs/linux/xfs_vnode.c +++ b/fs/xfs/linux/xfs_vnode.c @@ -213,6 +213,22 @@ vn_revalidate( inode->i_ctime = va.va_ctime; inode->i_atime = va.va_atime; i_size_write(inode, va.va_size); + 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 --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 950b50b9b6cf4..596d9400b9e17 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -388,6 +388,8 @@ xfs_acl_allow_set( 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 --git a/fs/xfs/xfs_cap.c b/fs/xfs/xfs_cap.c index 61731d7573a43..638dbe5be62f2 100644 --- a/fs/xfs/xfs_cap.c +++ b/fs/xfs/xfs_cap.c @@ -192,6 +192,8 @@ xfs_cap_allow_set( 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 --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index 0af61bc72bd54..86968706bae71 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h @@ -471,13 +471,21 @@ xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); * 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_ALL \ - (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) +#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_NODUMP_BIT 7 /* do not dump */ +#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_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) #endif /* __XFS_DINODE_H__ */ diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index d52e8146239c2..c2c3cc118f970 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -69,12 +69,14 @@ struct fsxattr { * There should be a one-to-one correspondence between these flags and the * XFS_DIFLAG_s. */ -#define XFS_XFLAG_REALTIME 0x00000001 -#define XFS_XFLAG_PREALLOC 0x00000002 +#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ +#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ +#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ +#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */ +#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ +#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ +#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ -#define XFS_XFLAG_ALL \ - ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR ) - /* * Structure for XFS_IOC_GETBMAP. diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index fe426e94b351a..2f95078422e29 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -1114,7 +1114,7 @@ xfs_dilocate( agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || ino != XFS_AGINO_TO_INO(mp, agno, agino)) { -#ifdef DEBUG +#if 0 if (agno >= mp->m_sb.sb_agcount) { xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: agno (%d) >= " diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 22d43d5d2bb3d..da144b220a076 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1197,6 +1197,8 @@ xfs_ialloc( ip->i_d.di_dmevmask = 0; ip->i_d.di_dmstate = 0; ip->i_d.di_flags = 0; + if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && xfs_inherit_nodump) + ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; flags = XFS_ILOG_CORE; switch (mode & IFMT) { case IFIFO: @@ -1210,6 +1212,8 @@ xfs_ialloc( break; case IFREG: case IFDIR: + if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && xfs_inherit_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 +3504,9 @@ xfs_iaccess( 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 +3630,7 @@ xfs_ichgtime(xfs_inode_t *ip, * 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 --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 50836e4864b45..8d09bfb2a9664 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -156,13 +156,23 @@ xfs_bulkstat_one( /* * convert di_flags to bs_xflags. */ - di_flags=INT_GET(dic->di_flags, arch); + di_flags = INT_GET(dic->di_flags, arch); buf->bs_xflags = ((di_flags & XFS_DIFLAG_REALTIME) ? 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) | + ((di_flags & XFS_DIFLAG_NODUMP) ? + XFS_XFLAG_NODUMP : 0) | (XFS_CFORK_Q_ARCH(dic, arch) ? XFS_XFLAG_HASATTR : 0); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 270af19d6e574..9f6622c28b48c 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -265,6 +265,16 @@ xfs_getattr( 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) | + ((ip->i_d.di_flags & XFS_DIFLAG_NODUMP) ? + XFS_XFLAG_NODUMP: 0) | (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; @@ -647,6 +657,20 @@ xfs_setattr( goto error_return; } } + + /* + * Can't modify an immutable/append-only file unless + * we have appropriate permission. + */ + if ((mask & XFS_AT_XFLAGS) && + (ip->i_d.di_flags & + (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || + (vap->va_xflags & + (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && + !capable(CAP_LINUX_IMMUTABLE)) { + code = XFS_ERROR(EPERM); + goto error_return; + } } /* @@ -832,6 +856,16 @@ xfs_setattr( 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; + if (vap->va_xflags & XFS_XFLAG_NODUMP) + ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; /* can't set PREALLOC this way, just ignore it */ } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); @@ -1634,7 +1668,7 @@ xfs_release( if ((((ip->i_d.di_mode & IFMT) == IFREG) && ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS)) && - (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC))) { + (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)))) { if ((error = xfs_inactive_free_eofblocks(mp, ip))) return (error); /* Update linux inode block count after free above */ @@ -1709,7 +1743,7 @@ xfs_inactive( if ((((ip->i_d.di_mode & IFMT) == IFREG) && ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS)) && - (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) || + (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)) || (ip->i_delayed_blks != 0))) { if ((error = xfs_inactive_free_eofblocks(mp, ip))) return (VN_INACTIVE_CACHE); diff --git a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c index f0a98f2845418..1f7daff612f4a 100644 --- a/fs/xfs/xfsidbg.c +++ b/fs/xfs/xfsidbg.c @@ -3021,6 +3021,12 @@ xfs_prdinode_core(xfs_dinode_core_t *dip, int convert) static char *diflags[] = { "realtime", /* XFS_DIFLAG_REALTIME */ "prealloc", /* XFS_DIFLAG_PREALLOC */ + "newrtbm", /* XFS_DIFLAG_NEWRTBM */ + "immutable", /* XFS_DIFLAG_IMMUTABLE */ + "append", /* XFS_DIFLAG_APPEND */ + "sync", /* XFS_DIFLAG_SYNC */ + "noatime", /* XFS_DIFLAG_NOATIME */ + "nodump", /* XFS_DIFLAG_NODUMP */ NULL }; -- 2.53.0