Whamcloud - gitweb
LU-9874 osd-ldiskfs: simplify project transfer codes
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / rhel7 / ext4-projid-xfs-ioctls.patch
1 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
2 index ce3b85f..29db502 100644
3 --- a/fs/ext4/ext4.h
4 +++ b/fs/ext4/ext4.h
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 */
8  
9 +#define EXT4_FL_XFLAG_VISIBLE          (EXT4_SYNC_FL | \
10 +                                        EXT4_IMMUTABLE_FL | \
11 +                                        EXT4_APPEND_FL | \
12 +                                        EXT4_NODUMP_FL | \
13 +                                        EXT4_NOATIME_FL | \
14 +                                        EXT4_PROJINHERIT_FL)
15 +
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)
22  
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)
27 +/*
28 + * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
29 + */
30 +struct fsxattr {
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];
36 +};
37 +
38 +/*
39 + * Flags for the fsx_xflags field
40 + */
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) */
57 +
58 +#define EXT4_IOC_FSGETXATTR            FS_IOC_FSGETXATTR
59 +#define EXT4_IOC_FSSETXATTR            FS_IOC_FSSETXATTR
60 +
61  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
62  /*
63   * ioctl commands in 32 bit emulation
64 @@ -2347,6 +2392,7 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
65  /* ioctl.c */
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);
69  
70  /* migrate.c */
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
74 --- a/fs/ext4/ioctl.c
75 +++ b/fs/ext4/ioctl.c
76 @@ -15,6 +15,7 @@
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"
82  #include "ext4.h"
83  
84 @@ -198,6 +199,294 @@ journal_err_out:
85         return err;
86  }
87  
88 +static int ext4_ioctl_setflags(struct inode *inode,
89 +                              unsigned int flags)
90 +{
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;
96 +       unsigned int jflag;
97 +
98 +       /* Is it quota file? Do not allow user to mess with it */
99 +       if (IS_NOQUOTA(inode))
100 +               goto flags_out;
101 +
102 +       oldflags = ei->i_flags;
103 +
104 +       /* The JOURNAL_DATA flag is modifiable only by root */
105 +       jflag = flags & EXT4_JOURNAL_DATA_FL;
106 +
107 +       /*
108 +        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
109 +        * the relevant capability.
110 +        *
111 +        * This test looks nicer. Thanks to Pauline Middelink
112 +        */
113 +       if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
114 +               if (!capable(CAP_LINUX_IMMUTABLE))
115 +                       goto flags_out;
116 +       }
117 +
118 +       /*
119 +        * The JOURNAL_DATA flag can only be changed by
120 +        * the relevant capability.
121 +        */
122 +       if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
123 +               if (!capable(CAP_SYS_RESOURCE))
124 +                       goto flags_out;
125 +       }
126 +       if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
127 +               migrate = 1;
128 +
129 +       if (flags & EXT4_EOFBLOCKS_FL) {
130 +               /* we don't support adding EOFBLOCKS flag */
131 +               if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
132 +                       err = -EOPNOTSUPP;
133 +                       goto flags_out;
134 +               }
135 +       } else if (oldflags & EXT4_EOFBLOCKS_FL)
136 +               ext4_truncate(inode);
137 +
138 +       handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
139 +       if (IS_ERR(handle)) {
140 +               err = PTR_ERR(handle);
141 +               goto flags_out;
142 +       }
143 +       if (IS_SYNC(inode))
144 +               ext4_handle_sync(handle);
145 +       err = ext4_reserve_inode_write(handle, inode, &iloc);
146 +       if (err)
147 +               goto flags_err;
148 +
149 +       for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
150 +               if (!(mask & EXT4_FL_USER_MODIFIABLE))
151 +                       continue;
152 +               if (mask & flags)
153 +                       ext4_set_inode_flag(inode, i);
154 +               else
155 +                       ext4_clear_inode_flag(inode, i);
156 +       }
157 +
158 +       ext4_set_inode_flags(inode);
159 +       inode->i_ctime = ext4_current_time(inode);
160 +
161 +       err = ext4_mark_iloc_dirty(handle, inode, &iloc);
162 +flags_err:
163 +       ext4_journal_stop(handle);
164 +       if (err)
165 +               goto flags_out;
166 +
167 +       if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
168 +               err = ext4_change_inode_journal_flag(inode, jflag);
169 +       if (err)
170 +               goto flags_out;
171 +       if (migrate) {
172 +               if (flags & EXT4_EXTENTS_FL)
173 +                       err = ext4_ext_migrate(inode);
174 +               else
175 +                       err = ext4_ind_migrate(inode);
176 +       }
177 +
178 +flags_out:
179 +       return err;
180 +}
181 +
182 +#ifdef CONFIG_QUOTA
183 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
184 +{
185 +       struct inode *inode = file_inode(filp);
186 +       struct super_block *sb = inode->i_sb;
187 +       struct ext4_inode_info *ei = EXT4_I(inode);
188 +       int err, rc;
189 +       handle_t *handle;
190 +       kprojid_t kprojid;
191 +       struct ext4_iloc iloc;
192 +       struct ext4_inode *raw_inode;
193 +       struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
194 +
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;
201 +               else
202 +                       return 0;
203 +       }
204 +
205 +       if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
206 +               return -EOPNOTSUPP;
207 +
208 +       kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
209 +
210 +       if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
211 +               return 0;
212 +
213 +       err = mnt_want_write_file(filp);
214 +       if (err)
215 +               return err;
216 +
217 +       err = -EPERM;
218 +       mutex_lock(&inode->i_mutex);
219 +       /* Is it quota file? Do not allow user to mess with it */
220 +       if (IS_NOQUOTA(inode))
221 +               goto out_unlock;
222 +
223 +       err = ext4_get_inode_loc(inode, &iloc);
224 +       if (err)
225 +               goto out_unlock;
226 +
227 +       raw_inode = ext4_raw_inode(&iloc);
228 +       if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
229 +               err = -EOVERFLOW;
230 +               brelse(iloc.bh);
231 +               goto out_unlock;
232 +       }
233 +       brelse(iloc.bh);
234 +
235 +       dquot_initialize(inode);
236 +
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);
242 +               goto out_unlock;
243 +       }
244 +
245 +       err = ext4_reserve_inode_write(handle, inode, &iloc);
246 +       if (err)
247 +               goto out_stop;
248 +
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]);
253 +               if (err)
254 +                       goto out_dirty;
255 +       }
256 +
257 +       EXT4_I(inode)->i_projid = kprojid;
258 +       inode->i_ctime = ext4_current_time(inode);
259 +out_dirty:
260 +       rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
261 +       if (!err)
262 +               err = rc;
263 +out_stop:
264 +       ext4_journal_stop(handle);
265 +out_unlock:
266 +       mutex_unlock(&inode->i_mutex);
267 +       mnt_drop_write_file(filp);
268 +       return err;
269 +
270 +
271 +}
272 +
273 +int ext4_transfer_project(struct inode *inode, __u32 projid)
274 +{
275 +       struct super_block *sb = inode->i_sb;
276 +       struct ext4_inode_info *ei = EXT4_I(inode);
277 +       int err;
278 +       kprojid_t kprojid;
279 +       struct ext4_iloc iloc;
280 +       struct ext4_inode *raw_inode;
281 +       struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
282 +
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;
289 +               else
290 +                       return 0;
291 +       }
292 +
293 +       if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
294 +               return -EOPNOTSUPP;
295 +
296 +       kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
297 +       if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
298 +               return 0;
299 +
300 +       err = ext4_get_inode_loc(inode, &iloc);
301 +       if (err)
302 +               return err;
303 +
304 +       raw_inode = ext4_raw_inode(&iloc);
305 +       if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
306 +               err = -EOVERFLOW;
307 +               brelse(iloc.bh);
308 +               return err;
309 +       }
310 +       brelse(iloc.bh);
311 +
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]);
317 +               if (err)
318 +                       return err;
319 +       }
320 +
321 +       return err;
322 +}
323 +EXPORT_SYMBOL(ext4_transfer_project);
324 +
325 +#else
326 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
327 +{
328 +       if (projid != EXT4_DEF_PROJID)
329 +               return -EOPNOTSUPP;
330 +       return 0;
331 +}
332 +#endif
333 +
334 +
335 +/* Transfer internal flags to xflags */
336 +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
337 +{
338 +       __u32 xflags = 0;
339 +
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;
352 +       return xflags;
353 +}
354 +
355 +/* Transfer xflags flags to internal */
356 +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
357 +{
358 +       unsigned long iflags = 0;
359 +
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;
372 +
373 +       return iflags;
374 +}
375 +
376  long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
377  {
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;
388 +               int err;
389  
390                 if (!inode_owner_or_capable(inode))
391                         return -EACCES;
392 @@ -231,89 +516,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
393  
394                 flags = ext4_mask_flags(inode->i_mode, flags);
395  
396 -               err = -EPERM;
397                 mutex_lock(&inode->i_mutex);
398 -               /* Is it quota file? Do not allow user to mess with it */
399 -               if (IS_NOQUOTA(inode))
400 -                       goto flags_out;
401 -
402 -               oldflags = ei->i_flags;
403 -
404 -               /* The JOURNAL_DATA flag is modifiable only by root */
405 -               jflag = flags & EXT4_JOURNAL_DATA_FL;
406 -
407 -               /*
408 -                * The IMMUTABLE and APPEND_ONLY flags can only be changed by
409 -                * the relevant capability.
410 -                *
411 -                * This test looks nicer. Thanks to Pauline Middelink
412 -                */
413 -               if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
414 -                       if (!capable(CAP_LINUX_IMMUTABLE))
415 -                               goto flags_out;
416 -               }
417 -
418 -               /*
419 -                * The JOURNAL_DATA flag can only be changed by
420 -                * the relevant capability.
421 -                */
422 -               if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
423 -                       if (!capable(CAP_SYS_RESOURCE))
424 -                               goto flags_out;
425 -               }
426 -               if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
427 -                       migrate = 1;
428 -
429 -               if (flags & EXT4_EOFBLOCKS_FL) {
430 -                       /* we don't support adding EOFBLOCKS flag */
431 -                       if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
432 -                               err = -EOPNOTSUPP;
433 -                               goto flags_out;
434 -                       }
435 -               } else if (oldflags & EXT4_EOFBLOCKS_FL)
436 -                       ext4_truncate(inode);
437 -
438 -               handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
439 -               if (IS_ERR(handle)) {
440 -                       err = PTR_ERR(handle);
441 -                       goto flags_out;
442 -               }
443 -               if (IS_SYNC(inode))
444 -                       ext4_handle_sync(handle);
445 -               err = ext4_reserve_inode_write(handle, inode, &iloc);
446 -               if (err)
447 -                       goto flags_err;
448 -
449 -               for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
450 -                       if (!(mask & EXT4_FL_USER_MODIFIABLE))
451 -                               continue;
452 -                       if (mask & flags)
453 -                               ext4_set_inode_flag(inode, i);
454 -                       else
455 -                               ext4_clear_inode_flag(inode, i);
456 -               }
457 -
458 -               ext4_set_inode_flags(inode);
459 -               inode->i_ctime = ext4_current_time(inode);
460 -
461 -               err = ext4_mark_iloc_dirty(handle, inode, &iloc);
462 -flags_err:
463 -               ext4_journal_stop(handle);
464 -               if (err)
465 -                       goto flags_out;
466 -
467 -               if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
468 -                       err = ext4_change_inode_journal_flag(inode, jflag);
469 -               if (err)
470 -                       goto flags_out;
471 -               if (migrate) {
472 -                       if (flags & EXT4_EXTENTS_FL)
473 -                               err = ext4_ext_migrate(inode);
474 -                       else
475 -                               err = ext4_ind_migrate(inode);
476 -               }
477 -
478 -flags_out:
479 +               err = ext4_ioctl_setflags(inode, flags);
480                 mutex_unlock(&inode->i_mutex);
481                 mnt_drop_write_file(filp);
482                 return err;
483 @@ -622,6 +826,62 @@ resizefs_out:
484         }
485         case EXT4_IOC_PRECACHE_EXTENTS:
486                 return ext4_ext_precache(inode);
487 +       case EXT4_IOC_FSGETXATTR:
488 +       {
489 +               struct fsxattr fa;
490 +               unsigned int flags;
491 +
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);
496 +
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);
501 +               }
502 +
503 +               if (copy_to_user((struct fsxattr __user *)arg,
504 +                                &fa, sizeof(fa)))
505 +                       return -EFAULT;
506 +               return 0;
507 +       }
508 +       case EXT4_IOC_FSSETXATTR:
509 +       {
510 +               struct fsxattr fa;
511 +               int err;
512 +
513 +               if (copy_from_user(&fa, (struct fsxattr __user *)arg,
514 +                                  sizeof(fa)))
515 +                       return -EFAULT;
516 +
517 +               /* Make sure caller has proper permission */
518 +               if (!inode_owner_or_capable(inode))
519 +                       return -EACCES;
520 +
521 +               err = mnt_want_write_file(filp);
522 +               if (err)
523 +                       return err;
524 +
525 +               flags = ext4_xflags_to_iflags(fa.fsx_xflags);
526 +               flags = ext4_mask_flags(inode->i_mode, flags);
527 +
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);
534 +               if (err)
535 +                       return err;
536 +
537 +               err = ext4_ioctl_setproject(filp, fa.fsx_projid);
538 +               if (err)
539 +                       return err;
540 +
541 +               return 0;
542 +       }
543  
544         default:
545                 return -ENOTTY;