1 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
2 index 00f317c..312abfd 100644
5 @@ -383,6 +383,13 @@ struct flex_groups {
6 #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
7 #define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
9 +#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
10 + EXT4_IMMUTABLE_FL | \
14 + EXT4_PROJINHERIT_FL)
16 /* Flags that should be inherited by new inodes from their parent. */
17 #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
18 EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
19 @@ -607,6 +614,8 @@ enum {
20 #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
21 #define EXT4_IOC_SWAP_BOOT _IO('f', 17)
22 #define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
23 +#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
24 +#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
26 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
28 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
29 index 70c66d3..5857658 100644
33 #include <linux/mount.h>
34 #include <linux/file.h>
35 #include <asm/uaccess.h>
36 +#include <linux/quotaops.h>
37 #include "ext4_jbd2.h"
40 @@ -198,6 +199,239 @@ journal_err_out:
44 +static int ext4_ioctl_setflags(struct inode *inode,
47 + struct ext4_inode_info *ei = EXT4_I(inode);
48 + handle_t *handle = NULL;
49 + int err = EPERM, migrate = 0;
50 + struct ext4_iloc iloc;
51 + unsigned int oldflags, mask, i;
54 + /* Is it quota file? Do not allow user to mess with it */
55 + if (IS_NOQUOTA(inode))
58 + oldflags = ei->i_flags;
60 + /* The JOURNAL_DATA flag is modifiable only by root */
61 + jflag = flags & EXT4_JOURNAL_DATA_FL;
64 + * The IMMUTABLE and APPEND_ONLY flags can only be changed by
65 + * the relevant capability.
67 + * This test looks nicer. Thanks to Pauline Middelink
69 + if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
70 + if (!capable(CAP_LINUX_IMMUTABLE))
75 + * The JOURNAL_DATA flag can only be changed by
76 + * the relevant capability.
78 + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
79 + if (!capable(CAP_SYS_RESOURCE))
82 + if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
85 + if (flags & EXT4_EOFBLOCKS_FL) {
86 + /* we don't support adding EOFBLOCKS flag */
87 + if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
91 + } else if (oldflags & EXT4_EOFBLOCKS_FL)
92 + ext4_truncate(inode);
94 + handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
95 + if (IS_ERR(handle)) {
96 + err = PTR_ERR(handle);
100 + ext4_handle_sync(handle);
101 + err = ext4_reserve_inode_write(handle, inode, &iloc);
105 + for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
106 + if (!(mask & EXT4_FL_USER_MODIFIABLE))
109 + ext4_set_inode_flag(inode, i);
111 + ext4_clear_inode_flag(inode, i);
114 + ext4_set_inode_flags(inode);
115 + inode->i_ctime = ext4_current_time(inode);
117 + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
119 + ext4_journal_stop(handle);
123 + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
124 + err = ext4_change_inode_journal_flag(inode, jflag);
128 + if (flags & EXT4_EXTENTS_FL)
129 + err = ext4_ext_migrate(inode);
131 + err = ext4_ind_migrate(inode);
139 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
141 + struct inode *inode = file_inode(filp);
142 + struct super_block *sb = inode->i_sb;
143 + struct ext4_inode_info *ei = EXT4_I(inode);
147 + struct ext4_iloc iloc;
148 + struct ext4_inode *raw_inode;
149 + struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
151 + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
152 + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
153 + BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
154 + != EXT4_DEF_PROJID);
155 + if (projid != EXT4_DEF_PROJID)
156 + return -EOPNOTSUPP;
161 + if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
162 + return -EOPNOTSUPP;
164 + kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
166 + if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
169 + err = mnt_want_write_file(filp);
174 + mutex_lock(&inode->i_mutex);
175 + /* Is it quota file? Do not allow user to mess with it */
176 + if (IS_NOQUOTA(inode))
179 + err = ext4_get_inode_loc(inode, &iloc);
183 + raw_inode = ext4_raw_inode(&iloc);
184 + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
191 + dquot_initialize(inode);
193 + handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
194 + EXT4_QUOTA_INIT_BLOCKS(sb) +
195 + EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
196 + if (IS_ERR(handle)) {
197 + err = PTR_ERR(handle);
201 + err = ext4_reserve_inode_write(handle, inode, &iloc);
205 + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
206 + if (transfer_to[PRJQUOTA]) {
207 + err = __dquot_transfer(inode, transfer_to);
208 + dqput(transfer_to[PRJQUOTA]);
213 + EXT4_I(inode)->i_projid = kprojid;
214 + inode->i_ctime = ext4_current_time(inode);
216 + rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
220 + ext4_journal_stop(handle);
222 + mutex_unlock(&inode->i_mutex);
223 + mnt_drop_write_file(filp);
227 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
229 + if (projid != EXT4_DEF_PROJID)
230 + return -EOPNOTSUPP;
236 +/* Transfer internal flags to xflags */
237 +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
241 + if (iflags & EXT4_SYNC_FL)
242 + xflags |= FS_XFLAG_SYNC;
243 + if (iflags & EXT4_IMMUTABLE_FL)
244 + xflags |= FS_XFLAG_IMMUTABLE;
245 + if (iflags & EXT4_APPEND_FL)
246 + xflags |= FS_XFLAG_APPEND;
247 + if (iflags & EXT4_NODUMP_FL)
248 + xflags |= FS_XFLAG_NODUMP;
249 + if (iflags & EXT4_NOATIME_FL)
250 + xflags |= FS_XFLAG_NOATIME;
251 + if (iflags & EXT4_PROJINHERIT_FL)
252 + xflags |= FS_XFLAG_PROJINHERIT;
256 +/* Transfer xflags flags to internal */
257 +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
259 + unsigned long iflags = 0;
261 + if (xflags & FS_XFLAG_SYNC)
262 + iflags |= EXT4_SYNC_FL;
263 + if (xflags & FS_XFLAG_IMMUTABLE)
264 + iflags |= EXT4_IMMUTABLE_FL;
265 + if (xflags & FS_XFLAG_APPEND)
266 + iflags |= EXT4_APPEND_FL;
267 + if (xflags & FS_XFLAG_NODUMP)
268 + iflags |= EXT4_NODUMP_FL;
269 + if (xflags & FS_XFLAG_NOATIME)
270 + iflags |= EXT4_NOATIME_FL;
271 + if (xflags & FS_XFLAG_PROJINHERIT)
272 + iflags |= EXT4_PROJINHERIT_FL;
277 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
279 struct inode *inode = file_inode(filp);
280 @@ -213,11 +447,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
281 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
282 return put_user(flags, (int __user *) arg);
283 case EXT4_IOC_SETFLAGS: {
284 - handle_t *handle = NULL;
285 - int err, migrate = 0;
286 - struct ext4_iloc iloc;
287 - unsigned int oldflags, mask, i;
288 - unsigned int jflag;
291 if (!inode_owner_or_capable(inode))
293 @@ -231,89 +461,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
295 flags = ext4_mask_flags(inode->i_mode, flags);
298 mutex_lock(&inode->i_mutex);
299 - /* Is it quota file? Do not allow user to mess with it */
300 - if (IS_NOQUOTA(inode))
303 - oldflags = ei->i_flags;
305 - /* The JOURNAL_DATA flag is modifiable only by root */
306 - jflag = flags & EXT4_JOURNAL_DATA_FL;
309 - * The IMMUTABLE and APPEND_ONLY flags can only be changed by
310 - * the relevant capability.
312 - * This test looks nicer. Thanks to Pauline Middelink
314 - if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
315 - if (!capable(CAP_LINUX_IMMUTABLE))
320 - * The JOURNAL_DATA flag can only be changed by
321 - * the relevant capability.
323 - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
324 - if (!capable(CAP_SYS_RESOURCE))
327 - if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
330 - if (flags & EXT4_EOFBLOCKS_FL) {
331 - /* we don't support adding EOFBLOCKS flag */
332 - if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
336 - } else if (oldflags & EXT4_EOFBLOCKS_FL)
337 - ext4_truncate(inode);
339 - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
340 - if (IS_ERR(handle)) {
341 - err = PTR_ERR(handle);
344 - if (IS_SYNC(inode))
345 - ext4_handle_sync(handle);
346 - err = ext4_reserve_inode_write(handle, inode, &iloc);
350 - for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
351 - if (!(mask & EXT4_FL_USER_MODIFIABLE))
354 - ext4_set_inode_flag(inode, i);
356 - ext4_clear_inode_flag(inode, i);
359 - ext4_set_inode_flags(inode);
360 - inode->i_ctime = ext4_current_time(inode);
362 - err = ext4_mark_iloc_dirty(handle, inode, &iloc);
364 - ext4_journal_stop(handle);
368 - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
369 - err = ext4_change_inode_journal_flag(inode, jflag);
373 - if (flags & EXT4_EXTENTS_FL)
374 - err = ext4_ext_migrate(inode);
376 - err = ext4_ind_migrate(inode);
380 + err = ext4_ioctl_setflags(inode, flags);
381 mutex_unlock(&inode->i_mutex);
382 mnt_drop_write_file(filp);
384 @@ -622,6 +771,62 @@ resizefs_out:
386 case EXT4_IOC_PRECACHE_EXTENTS:
387 return ext4_ext_precache(inode);
388 + case EXT4_IOC_FSGETXATTR:
391 + unsigned int flags;
393 + memset(&fa, 0, sizeof(struct fsxattr));
394 + ext4_get_inode_flags(ei);
395 + flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
396 + fa.fsx_xflags = ext4_iflags_to_xflags(flags);
398 + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
399 + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
400 + fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
401 + EXT4_I(inode)->i_projid);
404 + if (copy_to_user((struct fsxattr __user *)arg,
409 + case EXT4_IOC_FSSETXATTR:
414 + if (copy_from_user(&fa, (struct fsxattr __user *)arg,
418 + /* Make sure caller has proper permission */
419 + if (!inode_owner_or_capable(inode))
422 + err = mnt_want_write_file(filp);
426 + flags = ext4_xflags_to_iflags(fa.fsx_xflags);
427 + flags = ext4_mask_flags(inode->i_mode, flags);
429 + mutex_lock(&inode->i_mutex);
430 + flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
431 + (flags & EXT4_FL_XFLAG_VISIBLE);
432 + err = ext4_ioctl_setflags(inode, flags);
433 + mutex_unlock(&inode->i_mutex);
434 + mnt_drop_write_file(filp);
438 + err = ext4_ioctl_setproject(filp, fa.fsx_projid);