Whamcloud - gitweb
LU-4017 ldiskfs: add project quota support
[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 00f317c..312abfd 100644
3 --- a/fs/ext4/ext4.h
4 +++ b/fs/ext4/ext4.h
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 */
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 @@ -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
25  
26  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
27  /*
28 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
29 index 70c66d3..5857658 100644
30 --- a/fs/ext4/ioctl.c
31 +++ b/fs/ext4/ioctl.c
32 @@ -15,6 +15,7 @@
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"
38  #include "ext4.h"
39  
40 @@ -198,6 +199,239 @@ journal_err_out:
41         return err;
42  }
43  
44 +static int ext4_ioctl_setflags(struct inode *inode,
45 +                              unsigned int flags)
46 +{
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;
52 +       unsigned int jflag;
53 +
54 +       /* Is it quota file? Do not allow user to mess with it */
55 +       if (IS_NOQUOTA(inode))
56 +               goto flags_out;
57 +
58 +       oldflags = ei->i_flags;
59 +
60 +       /* The JOURNAL_DATA flag is modifiable only by root */
61 +       jflag = flags & EXT4_JOURNAL_DATA_FL;
62 +
63 +       /*
64 +        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
65 +        * the relevant capability.
66 +        *
67 +        * This test looks nicer. Thanks to Pauline Middelink
68 +        */
69 +       if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
70 +               if (!capable(CAP_LINUX_IMMUTABLE))
71 +                       goto flags_out;
72 +       }
73 +
74 +       /*
75 +        * The JOURNAL_DATA flag can only be changed by
76 +        * the relevant capability.
77 +        */
78 +       if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
79 +               if (!capable(CAP_SYS_RESOURCE))
80 +                       goto flags_out;
81 +       }
82 +       if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
83 +               migrate = 1;
84 +
85 +       if (flags & EXT4_EOFBLOCKS_FL) {
86 +               /* we don't support adding EOFBLOCKS flag */
87 +               if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
88 +                       err = -EOPNOTSUPP;
89 +                       goto flags_out;
90 +               }
91 +       } else if (oldflags & EXT4_EOFBLOCKS_FL)
92 +               ext4_truncate(inode);
93 +
94 +       handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
95 +       if (IS_ERR(handle)) {
96 +               err = PTR_ERR(handle);
97 +               goto flags_out;
98 +       }
99 +       if (IS_SYNC(inode))
100 +               ext4_handle_sync(handle);
101 +       err = ext4_reserve_inode_write(handle, inode, &iloc);
102 +       if (err)
103 +               goto flags_err;
104 +
105 +       for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
106 +               if (!(mask & EXT4_FL_USER_MODIFIABLE))
107 +                       continue;
108 +               if (mask & flags)
109 +                       ext4_set_inode_flag(inode, i);
110 +               else
111 +                       ext4_clear_inode_flag(inode, i);
112 +       }
113 +
114 +       ext4_set_inode_flags(inode);
115 +       inode->i_ctime = ext4_current_time(inode);
116 +
117 +       err = ext4_mark_iloc_dirty(handle, inode, &iloc);
118 +flags_err:
119 +       ext4_journal_stop(handle);
120 +       if (err)
121 +               goto flags_out;
122 +
123 +       if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
124 +               err = ext4_change_inode_journal_flag(inode, jflag);
125 +       if (err)
126 +               goto flags_out;
127 +       if (migrate) {
128 +               if (flags & EXT4_EXTENTS_FL)
129 +                       err = ext4_ext_migrate(inode);
130 +               else
131 +                       err = ext4_ind_migrate(inode);
132 +       }
133 +
134 +flags_out:
135 +       return err;
136 +}
137 +
138 +#ifdef CONFIG_QUOTA
139 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
140 +{
141 +       struct inode *inode = file_inode(filp);
142 +       struct super_block *sb = inode->i_sb;
143 +       struct ext4_inode_info *ei = EXT4_I(inode);
144 +       int err, rc;
145 +       handle_t *handle;
146 +       kprojid_t kprojid;
147 +       struct ext4_iloc iloc;
148 +       struct ext4_inode *raw_inode;
149 +       struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
150 +
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;
157 +               else
158 +                       return 0;
159 +       }
160 +
161 +       if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
162 +               return -EOPNOTSUPP;
163 +
164 +       kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
165 +
166 +       if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
167 +               return 0;
168 +
169 +       err = mnt_want_write_file(filp);
170 +       if (err)
171 +               return err;
172 +
173 +       err = -EPERM;
174 +       mutex_lock(&inode->i_mutex);
175 +       /* Is it quota file? Do not allow user to mess with it */
176 +       if (IS_NOQUOTA(inode))
177 +               goto out_unlock;
178 +
179 +       err = ext4_get_inode_loc(inode, &iloc);
180 +       if (err)
181 +               goto out_unlock;
182 +
183 +       raw_inode = ext4_raw_inode(&iloc);
184 +       if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
185 +               err = -EOVERFLOW;
186 +               brelse(iloc.bh);
187 +               goto out_unlock;
188 +       }
189 +       brelse(iloc.bh);
190 +
191 +       dquot_initialize(inode);
192 +
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);
198 +               goto out_unlock;
199 +       }
200 +
201 +       err = ext4_reserve_inode_write(handle, inode, &iloc);
202 +       if (err)
203 +               goto out_stop;
204 +
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]);
209 +               if (err)
210 +                       goto out_dirty;
211 +       }
212 +
213 +       EXT4_I(inode)->i_projid = kprojid;
214 +       inode->i_ctime = ext4_current_time(inode);
215 +out_dirty:
216 +       rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
217 +       if (!err)
218 +               err = rc;
219 +out_stop:
220 +       ext4_journal_stop(handle);
221 +out_unlock:
222 +       mutex_unlock(&inode->i_mutex);
223 +       mnt_drop_write_file(filp);
224 +       return err;
225 +}
226 +#else
227 +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
228 +{
229 +       if (projid != EXT4_DEF_PROJID)
230 +               return -EOPNOTSUPP;
231 +       return 0;
232 +}
233 +#endif
234 +
235 +
236 +/* Transfer internal flags to xflags */
237 +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
238 +{
239 +       __u32 xflags = 0;
240 +
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;
253 +       return xflags;
254 +}
255 +
256 +/* Transfer xflags flags to internal */
257 +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
258 +{
259 +       unsigned long iflags = 0;
260 +
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;
273 +
274 +       return iflags;
275 +}
276 +
277  long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
278  {
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;
289 +               int err;
290  
291                 if (!inode_owner_or_capable(inode))
292                         return -EACCES;
293 @@ -231,89 +461,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
294  
295                 flags = ext4_mask_flags(inode->i_mode, flags);
296  
297 -               err = -EPERM;
298                 mutex_lock(&inode->i_mutex);
299 -               /* Is it quota file? Do not allow user to mess with it */
300 -               if (IS_NOQUOTA(inode))
301 -                       goto flags_out;
302 -
303 -               oldflags = ei->i_flags;
304 -
305 -               /* The JOURNAL_DATA flag is modifiable only by root */
306 -               jflag = flags & EXT4_JOURNAL_DATA_FL;
307 -
308 -               /*
309 -                * The IMMUTABLE and APPEND_ONLY flags can only be changed by
310 -                * the relevant capability.
311 -                *
312 -                * This test looks nicer. Thanks to Pauline Middelink
313 -                */
314 -               if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
315 -                       if (!capable(CAP_LINUX_IMMUTABLE))
316 -                               goto flags_out;
317 -               }
318 -
319 -               /*
320 -                * The JOURNAL_DATA flag can only be changed by
321 -                * the relevant capability.
322 -                */
323 -               if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
324 -                       if (!capable(CAP_SYS_RESOURCE))
325 -                               goto flags_out;
326 -               }
327 -               if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
328 -                       migrate = 1;
329 -
330 -               if (flags & EXT4_EOFBLOCKS_FL) {
331 -                       /* we don't support adding EOFBLOCKS flag */
332 -                       if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
333 -                               err = -EOPNOTSUPP;
334 -                               goto flags_out;
335 -                       }
336 -               } else if (oldflags & EXT4_EOFBLOCKS_FL)
337 -                       ext4_truncate(inode);
338 -
339 -               handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
340 -               if (IS_ERR(handle)) {
341 -                       err = PTR_ERR(handle);
342 -                       goto flags_out;
343 -               }
344 -               if (IS_SYNC(inode))
345 -                       ext4_handle_sync(handle);
346 -               err = ext4_reserve_inode_write(handle, inode, &iloc);
347 -               if (err)
348 -                       goto flags_err;
349 -
350 -               for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
351 -                       if (!(mask & EXT4_FL_USER_MODIFIABLE))
352 -                               continue;
353 -                       if (mask & flags)
354 -                               ext4_set_inode_flag(inode, i);
355 -                       else
356 -                               ext4_clear_inode_flag(inode, i);
357 -               }
358 -
359 -               ext4_set_inode_flags(inode);
360 -               inode->i_ctime = ext4_current_time(inode);
361 -
362 -               err = ext4_mark_iloc_dirty(handle, inode, &iloc);
363 -flags_err:
364 -               ext4_journal_stop(handle);
365 -               if (err)
366 -                       goto flags_out;
367 -
368 -               if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
369 -                       err = ext4_change_inode_journal_flag(inode, jflag);
370 -               if (err)
371 -                       goto flags_out;
372 -               if (migrate) {
373 -                       if (flags & EXT4_EXTENTS_FL)
374 -                               err = ext4_ext_migrate(inode);
375 -                       else
376 -                               err = ext4_ind_migrate(inode);
377 -               }
378 -
379 -flags_out:
380 +               err = ext4_ioctl_setflags(inode, flags);
381                 mutex_unlock(&inode->i_mutex);
382                 mnt_drop_write_file(filp);
383                 return err;
384 @@ -622,6 +771,62 @@ resizefs_out:
385         }
386         case EXT4_IOC_PRECACHE_EXTENTS:
387                 return ext4_ext_precache(inode);
388 +       case EXT4_IOC_FSGETXATTR:
389 +       {
390 +               struct fsxattr fa;
391 +               unsigned int flags;
392 +
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);
397 +
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);
402 +               }
403 +
404 +               if (copy_to_user((struct fsxattr __user *)arg,
405 +                                &fa, sizeof(fa)))
406 +                       return -EFAULT;
407 +               return 0;
408 +       }
409 +       case EXT4_IOC_FSSETXATTR:
410 +       {
411 +               struct fsxattr fa;
412 +               int err;
413 +
414 +               if (copy_from_user(&fa, (struct fsxattr __user *)arg,
415 +                                  sizeof(fa)))
416 +                       return -EFAULT;
417 +
418 +               /* Make sure caller has proper permission */
419 +               if (!inode_owner_or_capable(inode))
420 +                       return -EACCES;
421 +
422 +               err = mnt_want_write_file(filp);
423 +               if (err)
424 +                       return err;
425 +
426 +               flags = ext4_xflags_to_iflags(fa.fsx_xflags);
427 +               flags = ext4_mask_flags(inode->i_mode, flags);
428 +
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);
435 +               if (err)
436 +                       return err;
437 +
438 +               err = ext4_ioctl_setproject(filp, fa.fsx_projid);
439 +               if (err)
440 +                       return err;
441 +
442 +               return 0;
443 +       }
444  
445         default:
446                 return -ENOTTY;