1 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
2 index ce3b85f..29db502 100644
5 @@ -395,6 +395,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 @@ -620,6 +627,44 @@ enum {
20 #define EXT4_IOC_SWAP_BOOT _IO('f', 17)
21 #define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
23 +#ifndef FS_IOC_FSGETXATTR
24 +/* Until the uapi changes get merged for project quota... */
25 +#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
26 +#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
28 + * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
31 + __u32 fsx_xflags; /* xflags field value (get/set) */
32 + __u32 fsx_extsize; /* extsize field value (get/set)*/
33 + __u32 fsx_nextents; /* nextents field value (get) */
34 + __u32 fsx_projid; /* project identifier (get/set) */
35 + unsigned char fsx_pad[12];
39 + * Flags for the fsx_xflags field
41 +#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
42 +#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
43 +#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
44 +#define FS_XFLAG_APPEND 0x00000010 /* all writes append */
45 +#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
46 +#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */
47 +#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
48 +#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
49 +#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
50 +#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
51 +#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
52 +#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
53 +#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
54 +#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
55 +#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
56 +#endif /* !defined(FS_IOC_FSGETXATTR) */
58 +#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
59 +#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
61 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
63 * ioctl commands in 32 bit emulation
64 @@ -2347,6 +2392,7 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
66 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
67 extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
68 +extern int ext4_transfer_project(struct inode *inode, __u32 projid);
71 extern int ext4_ext_migrate(struct inode *);
72 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
73 index 70c66d3..276d33d 100644
77 #include <linux/mount.h>
78 #include <linux/file.h>
79 #include <asm/uaccess.h>
80 +#include <linux/quotaops.h>
81 #include "ext4_jbd2.h"
84 @@ -198,6 +199,294 @@ journal_err_out:
88 +static int ext4_ioctl_setflags(struct inode *inode,
91 + struct ext4_inode_info *ei = EXT4_I(inode);
92 + handle_t *handle = NULL;
93 + int err = EPERM, migrate = 0;
94 + struct ext4_iloc iloc;
95 + unsigned int oldflags, mask, i;
98 + /* Is it quota file? Do not allow user to mess with it */
99 + if (IS_NOQUOTA(inode))
102 + oldflags = ei->i_flags;
104 + /* The JOURNAL_DATA flag is modifiable only by root */
105 + jflag = flags & EXT4_JOURNAL_DATA_FL;
108 + * The IMMUTABLE and APPEND_ONLY flags can only be changed by
109 + * the relevant capability.
111 + * This test looks nicer. Thanks to Pauline Middelink
113 + if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
114 + if (!capable(CAP_LINUX_IMMUTABLE))
119 + * The JOURNAL_DATA flag can only be changed by
120 + * the relevant capability.
122 + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
123 + if (!capable(CAP_SYS_RESOURCE))
126 + if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
129 + if (flags & EXT4_EOFBLOCKS_FL) {
130 + /* we don't support adding EOFBLOCKS flag */
131 + if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
135 + } else if (oldflags & EXT4_EOFBLOCKS_FL)
136 + ext4_truncate(inode);
138 + handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
139 + if (IS_ERR(handle)) {
140 + err = PTR_ERR(handle);
143 + if (IS_SYNC(inode))
144 + ext4_handle_sync(handle);
145 + err = ext4_reserve_inode_write(handle, inode, &iloc);
149 + for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
150 + if (!(mask & EXT4_FL_USER_MODIFIABLE))
153 + ext4_set_inode_flag(inode, i);
155 + ext4_clear_inode_flag(inode, i);
158 + ext4_set_inode_flags(inode);
159 + inode->i_ctime = ext4_current_time(inode);
161 + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
163 + ext4_journal_stop(handle);
167 + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
168 + err = ext4_change_inode_journal_flag(inode, jflag);
172 + if (flags & EXT4_EXTENTS_FL)
173 + err = ext4_ext_migrate(inode);
175 + err = ext4_ind_migrate(inode);
183 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
185 + struct inode *inode = file_inode(filp);
186 + struct super_block *sb = inode->i_sb;
187 + struct ext4_inode_info *ei = EXT4_I(inode);
191 + struct ext4_iloc iloc;
192 + struct ext4_inode *raw_inode;
193 + struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
195 + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
196 + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
197 + BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
198 + != EXT4_DEF_PROJID);
199 + if (projid != EXT4_DEF_PROJID)
200 + return -EOPNOTSUPP;
205 + if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
206 + return -EOPNOTSUPP;
208 + kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
210 + if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
213 + err = mnt_want_write_file(filp);
218 + mutex_lock(&inode->i_mutex);
219 + /* Is it quota file? Do not allow user to mess with it */
220 + if (IS_NOQUOTA(inode))
223 + err = ext4_get_inode_loc(inode, &iloc);
227 + raw_inode = ext4_raw_inode(&iloc);
228 + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
235 + dquot_initialize(inode);
237 + handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
238 + EXT4_QUOTA_INIT_BLOCKS(sb) +
239 + EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
240 + if (IS_ERR(handle)) {
241 + err = PTR_ERR(handle);
245 + err = ext4_reserve_inode_write(handle, inode, &iloc);
249 + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
250 + if (transfer_to[PRJQUOTA]) {
251 + err = __dquot_transfer(inode, transfer_to);
252 + dqput(transfer_to[PRJQUOTA]);
257 + EXT4_I(inode)->i_projid = kprojid;
258 + inode->i_ctime = ext4_current_time(inode);
260 + rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
264 + ext4_journal_stop(handle);
266 + mutex_unlock(&inode->i_mutex);
267 + mnt_drop_write_file(filp);
273 +int ext4_transfer_project(struct inode *inode, __u32 projid)
275 + struct super_block *sb = inode->i_sb;
276 + struct ext4_inode_info *ei = EXT4_I(inode);
279 + struct ext4_iloc iloc;
280 + struct ext4_inode *raw_inode;
281 + struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
283 + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
284 + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
285 + BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
286 + != EXT4_DEF_PROJID);
287 + if (projid != EXT4_DEF_PROJID)
288 + return -EOPNOTSUPP;
293 + if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
294 + return -EOPNOTSUPP;
296 + kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
297 + if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
300 + err = ext4_get_inode_loc(inode, &iloc);
304 + raw_inode = ext4_raw_inode(&iloc);
305 + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
312 + dquot_initialize(inode);
313 + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
314 + if (transfer_to[PRJQUOTA]) {
315 + err = __dquot_transfer(inode, transfer_to);
316 + dqput(transfer_to[PRJQUOTA]);
323 +EXPORT_SYMBOL(ext4_transfer_project);
326 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
328 + if (projid != EXT4_DEF_PROJID)
329 + return -EOPNOTSUPP;
335 +/* Transfer internal flags to xflags */
336 +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
340 + if (iflags & EXT4_SYNC_FL)
341 + xflags |= FS_XFLAG_SYNC;
342 + if (iflags & EXT4_IMMUTABLE_FL)
343 + xflags |= FS_XFLAG_IMMUTABLE;
344 + if (iflags & EXT4_APPEND_FL)
345 + xflags |= FS_XFLAG_APPEND;
346 + if (iflags & EXT4_NODUMP_FL)
347 + xflags |= FS_XFLAG_NODUMP;
348 + if (iflags & EXT4_NOATIME_FL)
349 + xflags |= FS_XFLAG_NOATIME;
350 + if (iflags & EXT4_PROJINHERIT_FL)
351 + xflags |= FS_XFLAG_PROJINHERIT;
355 +/* Transfer xflags flags to internal */
356 +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
358 + unsigned long iflags = 0;
360 + if (xflags & FS_XFLAG_SYNC)
361 + iflags |= EXT4_SYNC_FL;
362 + if (xflags & FS_XFLAG_IMMUTABLE)
363 + iflags |= EXT4_IMMUTABLE_FL;
364 + if (xflags & FS_XFLAG_APPEND)
365 + iflags |= EXT4_APPEND_FL;
366 + if (xflags & FS_XFLAG_NODUMP)
367 + iflags |= EXT4_NODUMP_FL;
368 + if (xflags & FS_XFLAG_NOATIME)
369 + iflags |= EXT4_NOATIME_FL;
370 + if (xflags & FS_XFLAG_PROJINHERIT)
371 + iflags |= EXT4_PROJINHERIT_FL;
376 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
378 struct inode *inode = file_inode(filp);
379 @@ -213,11 +502,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
380 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
381 return put_user(flags, (int __user *) arg);
382 case EXT4_IOC_SETFLAGS: {
383 - handle_t *handle = NULL;
384 - int err, migrate = 0;
385 - struct ext4_iloc iloc;
386 - unsigned int oldflags, mask, i;
387 - unsigned int jflag;
390 if (!inode_owner_or_capable(inode))
392 @@ -231,89 +516,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
394 flags = ext4_mask_flags(inode->i_mode, flags);
397 mutex_lock(&inode->i_mutex);
398 - /* Is it quota file? Do not allow user to mess with it */
399 - if (IS_NOQUOTA(inode))
402 - oldflags = ei->i_flags;
404 - /* The JOURNAL_DATA flag is modifiable only by root */
405 - jflag = flags & EXT4_JOURNAL_DATA_FL;
408 - * The IMMUTABLE and APPEND_ONLY flags can only be changed by
409 - * the relevant capability.
411 - * This test looks nicer. Thanks to Pauline Middelink
413 - if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
414 - if (!capable(CAP_LINUX_IMMUTABLE))
419 - * The JOURNAL_DATA flag can only be changed by
420 - * the relevant capability.
422 - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
423 - if (!capable(CAP_SYS_RESOURCE))
426 - if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
429 - if (flags & EXT4_EOFBLOCKS_FL) {
430 - /* we don't support adding EOFBLOCKS flag */
431 - if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
435 - } else if (oldflags & EXT4_EOFBLOCKS_FL)
436 - ext4_truncate(inode);
438 - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
439 - if (IS_ERR(handle)) {
440 - err = PTR_ERR(handle);
443 - if (IS_SYNC(inode))
444 - ext4_handle_sync(handle);
445 - err = ext4_reserve_inode_write(handle, inode, &iloc);
449 - for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
450 - if (!(mask & EXT4_FL_USER_MODIFIABLE))
453 - ext4_set_inode_flag(inode, i);
455 - ext4_clear_inode_flag(inode, i);
458 - ext4_set_inode_flags(inode);
459 - inode->i_ctime = ext4_current_time(inode);
461 - err = ext4_mark_iloc_dirty(handle, inode, &iloc);
463 - ext4_journal_stop(handle);
467 - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
468 - err = ext4_change_inode_journal_flag(inode, jflag);
472 - if (flags & EXT4_EXTENTS_FL)
473 - err = ext4_ext_migrate(inode);
475 - err = ext4_ind_migrate(inode);
479 + err = ext4_ioctl_setflags(inode, flags);
480 mutex_unlock(&inode->i_mutex);
481 mnt_drop_write_file(filp);
483 @@ -622,6 +826,62 @@ resizefs_out:
485 case EXT4_IOC_PRECACHE_EXTENTS:
486 return ext4_ext_precache(inode);
487 + case EXT4_IOC_FSGETXATTR:
490 + unsigned int flags;
492 + memset(&fa, 0, sizeof(struct fsxattr));
493 + ext4_get_inode_flags(ei);
494 + flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
495 + fa.fsx_xflags = ext4_iflags_to_xflags(flags);
497 + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
498 + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
499 + fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
500 + EXT4_I(inode)->i_projid);
503 + if (copy_to_user((struct fsxattr __user *)arg,
508 + case EXT4_IOC_FSSETXATTR:
513 + if (copy_from_user(&fa, (struct fsxattr __user *)arg,
517 + /* Make sure caller has proper permission */
518 + if (!inode_owner_or_capable(inode))
521 + err = mnt_want_write_file(filp);
525 + flags = ext4_xflags_to_iflags(fa.fsx_xflags);
526 + flags = ext4_mask_flags(inode->i_mode, flags);
528 + mutex_lock(&inode->i_mutex);
529 + flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
530 + (flags & EXT4_FL_XFLAG_VISIBLE);
531 + err = ext4_ioctl_setflags(inode, flags);
532 + mutex_unlock(&inode->i_mutex);
533 + mnt_drop_write_file(filp);
537 + err = ext4_ioctl_setproject(filp, fa.fsx_projid);