Commit 57b6451f authored by Nathan Scott's avatar Nathan Scott Committed by Stephen Lord

[XFS] Implement several additional inode flags - immutable, append-only, etc;...

[XFS] Implement several additional inode flags - immutable, append-only, etc; contributed by Ethan Benson.

SGI Modid: 2.5.x-xfs:slinx:158362a
parent 9f001d18
...@@ -59,6 +59,8 @@ xfs_param_t xfs_params = { ...@@ -59,6 +59,8 @@ xfs_param_t xfs_params = {
.error_level = { 0, 3, 11 }, .error_level = { 0, 3, 11 },
.sync_interval = { HZ, 30*HZ, 60*HZ }, .sync_interval = { HZ, 30*HZ, 60*HZ },
.stats_clear = { 0, 0, 1 }, .stats_clear = { 0, 0, 1 },
.inherit_sync = { 0, 1, 1 },
.inherit_nodump = { 0, 1, 1 },
}; };
/* /*
......
...@@ -72,6 +72,13 @@ ...@@ -72,6 +72,13 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
/*
* 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 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
...@@ -328,6 +335,17 @@ xfs_open_by_handle( ...@@ -328,6 +335,17 @@ xfs_open_by_handle(
if (permflag & O_TRUNC) if (permflag & O_TRUNC)
permflag |= 2; 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. */ /* Can't write directories. */
if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
iput(inode); iput(inode);
...@@ -429,6 +447,11 @@ xfs_fssetdm_by_handle( ...@@ -429,6 +447,11 @@ xfs_fssetdm_by_handle(
if (error) if (error)
return -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))) { if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
VN_RELE(vp); VN_RELE(vp);
return -XFS_ERROR(EFAULT); return -XFS_ERROR(EFAULT);
...@@ -514,11 +537,19 @@ xfs_attrmulti_by_handle( ...@@ -514,11 +537,19 @@ xfs_attrmulti_by_handle(
NULL, ops[i].am_error); NULL, ops[i].am_error);
break; break;
case ATTR_OP_SET: 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, VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
ops[i].am_length, ops[i].am_flags, ops[i].am_length, ops[i].am_flags,
NULL, ops[i].am_error); NULL, ops[i].am_error);
break; break;
case ATTR_OP_REMOVE: 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, VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
NULL, ops[i].am_error); NULL, ops[i].am_error);
break; break;
...@@ -566,6 +597,7 @@ xfs_ioc_fsgeometry( ...@@ -566,6 +597,7 @@ xfs_ioc_fsgeometry(
STATIC int STATIC int
xfs_ioc_xattr( xfs_ioc_xattr(
vnode_t *vp, vnode_t *vp,
xfs_inode_t *ip,
struct file *filp, struct file *filp,
unsigned int cmd, unsigned int cmd,
unsigned long arg); unsigned long arg);
...@@ -648,10 +680,13 @@ xfs_ioctl( ...@@ -648,10 +680,13 @@ xfs_ioctl(
case XFS_IOC_FSGEOMETRY: case XFS_IOC_FSGEOMETRY:
return xfs_ioc_fsgeometry(mp, arg); 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_FSGETXATTR:
case XFS_IOC_FSSETXATTR: case XFS_IOC_FSSETXATTR:
case XFS_IOC_FSGETXATTRA: 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: { case XFS_IOC_FSSETDM: {
struct fsdmidata dmi; struct fsdmidata dmi;
...@@ -837,6 +872,9 @@ xfs_ioc_space( ...@@ -837,6 +872,9 @@ xfs_ioc_space(
int attr_flags = 0; int attr_flags = 0;
int error; int error;
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
return -XFS_ERROR(EPERM);
if (filp->f_flags & O_RDONLY) if (filp->f_flags & O_RDONLY)
return -XFS_ERROR(EBADF); return -XFS_ERROR(EBADF);
...@@ -957,9 +995,50 @@ xfs_ioc_fsgeometry( ...@@ -957,9 +995,50 @@ xfs_ioc_fsgeometry(
return 0; 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 STATIC int
xfs_ioc_xattr( xfs_ioc_xattr(
vnode_t *vp, vnode_t *vp,
xfs_inode_t *ip,
struct file *filp, struct file *filp,
unsigned int cmd, unsigned int cmd,
unsigned long arg) unsigned long arg)
...@@ -967,6 +1046,8 @@ xfs_ioc_xattr( ...@@ -967,6 +1046,8 @@ xfs_ioc_xattr(
struct fsxattr fa; struct fsxattr fa;
vattr_t va; vattr_t va;
int error; int error;
int attr_flags;
unsigned int flags;
switch (cmd) { switch (cmd) {
case XFS_IOC_FSGETXATTR: { case XFS_IOC_FSGETXATTR: {
...@@ -985,24 +1066,24 @@ xfs_ioc_xattr( ...@@ -985,24 +1066,24 @@ xfs_ioc_xattr(
} }
case XFS_IOC_FSSETXATTR: { case XFS_IOC_FSSETXATTR: {
int attr_flags = 0;
if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa)))
return -XFS_ERROR(EFAULT); 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_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
va.va_xflags = fa.fsx_xflags; va.va_xflags = fa.fsx_xflags;
va.va_extsize = fa.fsx_extsize; 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); VOP_SETATTR(vp, &va, attr_flags, NULL, error);
if (!error)
vn_revalidate(vp); /* update Linux inode flags */
return -error; return -error;
} }
case XFS_IOC_FSGETXATTRA: { case XFS_IOC_FSGETXATTRA: {
va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS;
VOP_GETATTR(vp, &va, 0, NULL, error); VOP_GETATTR(vp, &va, 0, NULL, error);
if (error) if (error)
...@@ -1017,9 +1098,54 @@ xfs_ioc_xattr( ...@@ -1017,9 +1098,54 @@ xfs_ioc_xattr(
return 0; 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: default:
return -ENOTTY; return -ENOTTY;
} }
} }
......
...@@ -638,6 +638,9 @@ linvfs_setxattr( ...@@ -638,6 +638,9 @@ linvfs_setxattr(
return error; return error;
} }
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
/* Convert Linux syscall to XFS internal ATTR flags */ /* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE) if (flags & XATTR_CREATE)
xflags |= ATTR_CREATE; xflags |= ATTR_CREATE;
...@@ -787,6 +790,9 @@ linvfs_removexattr( ...@@ -787,6 +790,9 @@ linvfs_removexattr(
return error; return error;
} }
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
xfs_namespaces[ROOT_NAMES].namelen) == 0) { xfs_namespaces[ROOT_NAMES].namelen) == 0) {
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
......
...@@ -96,6 +96,8 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) ...@@ -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_error_level xfs_params.error_level.val
#define xfs_syncd_interval xfs_params.sync_interval.val #define xfs_syncd_interval xfs_params.sync_interval.val
#define xfs_stats_clear xfs_params.stats_clear.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 NBPP PAGE_SIZE
#define DPPSHFT (PAGE_SHIFT - 9) #define DPPSHFT (PAGE_SHIFT - 9)
......
...@@ -187,7 +187,22 @@ xfs_revalidate_inode( ...@@ -187,7 +187,22 @@ xfs_revalidate_inode(
inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; 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_sec = ip->i_d.di_ctime.t_sec;
inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; 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; vp->v_flag &= ~VMODIFIED;
} }
......
...@@ -97,6 +97,16 @@ STATIC ctl_table xfs_table[] = { ...@@ -97,6 +97,16 @@ STATIC ctl_table xfs_table[] = {
&sysctl_intvec, NULL, &sysctl_intvec, NULL,
&xfs_params.sync_interval.min, &xfs_params.sync_interval.max}, &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 */ /* please keep this the last entry */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
{XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
......
...@@ -55,6 +55,8 @@ typedef struct xfs_param { ...@@ -55,6 +55,8 @@ typedef struct xfs_param {
xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ 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 sync_interval; /* time between sync calls */
xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ 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; } xfs_param_t;
/* /*
...@@ -73,13 +75,15 @@ typedef struct xfs_param { ...@@ -73,13 +75,15 @@ typedef struct xfs_param {
*/ */
enum { enum {
XFS_RESTRICT_CHOWN = 1, XFS_RESTRICT_CHOWN = 3,
XFS_SGID_INHERIT = 2, XFS_SGID_INHERIT = 4,
XFS_SYMLINK_MODE = 3, XFS_SYMLINK_MODE = 5,
XFS_PANIC_MASK = 4, XFS_PANIC_MASK = 6,
XFS_ERRLEVEL = 5, XFS_ERRLEVEL = 7,
XFS_SYNC_INTERVAL = 6, XFS_SYNC_INTERVAL = 8,
XFS_STATS_CLEAR = 7, XFS_STATS_CLEAR = 12,
XFS_INHERIT_SYNC = 13,
XFS_INHERIT_NODUMP = 14,
}; };
extern xfs_param_t xfs_params; extern xfs_param_t xfs_params;
......
...@@ -213,6 +213,22 @@ vn_revalidate( ...@@ -213,6 +213,22 @@ vn_revalidate(
inode->i_ctime = va.va_ctime; inode->i_ctime = va.va_ctime;
inode->i_atime = va.va_atime; inode->i_atime = va.va_atime;
i_size_write(inode, va.va_size); 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); VUNMODIFY(vp);
} }
return -error; return -error;
......
...@@ -388,6 +388,8 @@ xfs_acl_allow_set( ...@@ -388,6 +388,8 @@ xfs_acl_allow_set(
vattr_t va; vattr_t va;
int error; int error;
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
return EPERM;
if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR) if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR)
return ENOTDIR; return ENOTDIR;
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
......
...@@ -192,6 +192,8 @@ xfs_cap_allow_set( ...@@ -192,6 +192,8 @@ xfs_cap_allow_set(
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return EROFS; return EROFS;
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
return EPERM;
if ((error = _MAC_VACCESS(vp, NULL, VWRITE))) if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
return error; return error;
va.va_mask = XFS_AT_UID; va.va_mask = XFS_AT_UID;
......
...@@ -471,13 +471,21 @@ xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); ...@@ -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 * There should be a one-to-one correspondence between these flags and the
* XFS_XFLAG_s. * XFS_XFLAG_s.
*/ */
#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ #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_PREALLOC_BIT 1 /* file space has been preallocated */
#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ #define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */
#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */
#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */
#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) #define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */
#define XFS_DIFLAG_ALL \ #define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */
(XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) #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__ */ #endif /* __XFS_DINODE_H__ */
...@@ -69,12 +69,14 @@ struct fsxattr { ...@@ -69,12 +69,14 @@ struct fsxattr {
* There should be a one-to-one correspondence between these flags and the * There should be a one-to-one correspondence between these flags and the
* XFS_DIFLAG_s. * XFS_DIFLAG_s.
*/ */
#define XFS_XFLAG_REALTIME 0x00000001 #define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
#define XFS_XFLAG_PREALLOC 0x00000002 #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_HASATTR 0x80000000 /* no DIFLAG for this */
#define XFS_XFLAG_ALL \
( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR )
/* /*
* Structure for XFS_IOC_GETBMAP. * Structure for XFS_IOC_GETBMAP.
......
...@@ -1114,7 +1114,7 @@ xfs_dilocate( ...@@ -1114,7 +1114,7 @@ xfs_dilocate(
agbno = XFS_AGINO_TO_AGBNO(mp, agino); agbno = XFS_AGINO_TO_AGBNO(mp, agino);
if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
ino != XFS_AGINO_TO_INO(mp, agno, agino)) { ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
#ifdef DEBUG #if 0
if (agno >= mp->m_sb.sb_agcount) { if (agno >= mp->m_sb.sb_agcount) {
xfs_fs_cmn_err(CE_ALERT, mp, xfs_fs_cmn_err(CE_ALERT, mp,
"xfs_dilocate: agno (%d) >= " "xfs_dilocate: agno (%d) >= "
......
...@@ -1197,6 +1197,8 @@ xfs_ialloc( ...@@ -1197,6 +1197,8 @@ xfs_ialloc(
ip->i_d.di_dmevmask = 0; ip->i_d.di_dmevmask = 0;
ip->i_d.di_dmstate = 0; ip->i_d.di_dmstate = 0;
ip->i_d.di_flags = 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; flags = XFS_ILOG_CORE;
switch (mode & IFMT) { switch (mode & IFMT) {
case IFIFO: case IFIFO:
...@@ -1210,6 +1212,8 @@ xfs_ialloc( ...@@ -1210,6 +1212,8 @@ xfs_ialloc(
break; break;
case IFREG: case IFREG:
case IFDIR: case IFDIR:
if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && xfs_inherit_sync)
ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
case IFLNK: case IFLNK:
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS;
...@@ -3500,6 +3504,9 @@ xfs_iaccess( ...@@ -3500,6 +3504,9 @@ xfs_iaccess(
if (IS_RDONLY(inode) && if (IS_RDONLY(inode) &&
(S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode))) (S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode)))
return XFS_ERROR(EROFS); return XFS_ERROR(EROFS);
if (IS_IMMUTABLE(inode))
return XFS_ERROR(EACCES);
} }
/* /*
...@@ -3623,7 +3630,7 @@ xfs_ichgtime(xfs_inode_t *ip, ...@@ -3623,7 +3630,7 @@ xfs_ichgtime(xfs_inode_t *ip,
* Don't update access timestamps on reads if mounted "noatime" * Don't update access timestamps on reads if mounted "noatime"
* Throw it away if anyone asks us. * 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)) ((flags & (XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD|XFS_ICHGTIME_CHG))
== XFS_ICHGTIME_ACC)) == XFS_ICHGTIME_ACC))
return; return;
......
...@@ -156,13 +156,23 @@ xfs_bulkstat_one( ...@@ -156,13 +156,23 @@ xfs_bulkstat_one(
/* /*
* convert di_flags to bs_xflags. * 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 = buf->bs_xflags =
((di_flags & XFS_DIFLAG_REALTIME) ? ((di_flags & XFS_DIFLAG_REALTIME) ?
XFS_XFLAG_REALTIME : 0) | XFS_XFLAG_REALTIME : 0) |
((di_flags & XFS_DIFLAG_PREALLOC) ? ((di_flags & XFS_DIFLAG_PREALLOC) ?
XFS_XFLAG_PREALLOC : 0) | 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_CFORK_Q_ARCH(dic, arch) ?
XFS_XFLAG_HASATTR : 0); XFS_XFLAG_HASATTR : 0);
......
...@@ -265,6 +265,16 @@ xfs_getattr( ...@@ -265,6 +265,16 @@ xfs_getattr(
XFS_XFLAG_REALTIME : 0) | XFS_XFLAG_REALTIME : 0) |
((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ? ((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ?
XFS_XFLAG_PREALLOC : 0) | 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_IFORK_Q(ip) ?
XFS_XFLAG_HASATTR : 0); XFS_XFLAG_HASATTR : 0);
vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog;
...@@ -647,6 +657,20 @@ xfs_setattr( ...@@ -647,6 +657,20 @@ xfs_setattr(
goto error_return; 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( ...@@ -832,6 +856,16 @@ xfs_setattr(
ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
ip->i_iocore.io_flags |= XFS_IOCORE_RT; 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 */ /* can't set PREALLOC this way, just ignore it */
} }
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
...@@ -1634,7 +1668,7 @@ xfs_release( ...@@ -1634,7 +1668,7 @@ xfs_release(
if ((((ip->i_d.di_mode & IFMT) == IFREG) && if ((((ip->i_d.di_mode & IFMT) == IFREG) &&
((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS)) && (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))) if ((error = xfs_inactive_free_eofblocks(mp, ip)))
return (error); return (error);
/* Update linux inode block count after free above */ /* Update linux inode block count after free above */
...@@ -1709,7 +1743,7 @@ xfs_inactive( ...@@ -1709,7 +1743,7 @@ xfs_inactive(
if ((((ip->i_d.di_mode & IFMT) == IFREG) && if ((((ip->i_d.di_mode & IFMT) == IFREG) &&
((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS)) && (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))) { (ip->i_delayed_blks != 0))) {
if ((error = xfs_inactive_free_eofblocks(mp, ip))) if ((error = xfs_inactive_free_eofblocks(mp, ip)))
return (VN_INACTIVE_CACHE); return (VN_INACTIVE_CACHE);
......
...@@ -3021,6 +3021,12 @@ xfs_prdinode_core(xfs_dinode_core_t *dip, int convert) ...@@ -3021,6 +3021,12 @@ xfs_prdinode_core(xfs_dinode_core_t *dip, int convert)
static char *diflags[] = { static char *diflags[] = {
"realtime", /* XFS_DIFLAG_REALTIME */ "realtime", /* XFS_DIFLAG_REALTIME */
"prealloc", /* XFS_DIFLAG_PREALLOC */ "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 NULL
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment