diff options
author | Li Xi <pkuelelixi@gmail.com> | 2016-01-08 16:01:22 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-01-08 16:01:22 -0500 |
commit | 9b7365fc1c82038faa52d56173b20221cf422cbe (patch) | |
tree | 3539021199fa3ec68cbca55e2689e7d741b66959 /fs | |
parent | 689c958cbe6be4f211b40747951a3ba2c73b6715 (diff) |
ext4: add FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
support for ext4. The interface is kept consistent with
XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 47 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 376 |
2 files changed, 336 insertions, 87 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 96cc151d5931..1c127213363a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -381,6 +381,13 @@ struct flex_groups { | |||
381 | #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */ | 381 | #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */ |
382 | #define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */ | 382 | #define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */ |
383 | 383 | ||
384 | #define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \ | ||
385 | EXT4_IMMUTABLE_FL | \ | ||
386 | EXT4_APPEND_FL | \ | ||
387 | EXT4_NODUMP_FL | \ | ||
388 | EXT4_NOATIME_FL | \ | ||
389 | EXT4_PROJINHERIT_FL) | ||
390 | |||
384 | /* Flags that should be inherited by new inodes from their parent. */ | 391 | /* Flags that should be inherited by new inodes from their parent. */ |
385 | #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ | 392 | #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ |
386 | EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ | 393 | EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ |
@@ -619,6 +626,46 @@ enum { | |||
619 | #define EXT4_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) | 626 | #define EXT4_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) |
620 | #define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) | 627 | #define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) |
621 | 628 | ||
629 | #ifndef FS_IOC_FSGETXATTR | ||
630 | /* Until the uapi changes get merged for project quota... */ | ||
631 | |||
632 | #define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) | ||
633 | #define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) | ||
634 | |||
635 | /* | ||
636 | * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR. | ||
637 | */ | ||
638 | struct fsxattr { | ||
639 | __u32 fsx_xflags; /* xflags field value (get/set) */ | ||
640 | __u32 fsx_extsize; /* extsize field value (get/set)*/ | ||
641 | __u32 fsx_nextents; /* nextents field value (get) */ | ||
642 | __u32 fsx_projid; /* project identifier (get/set) */ | ||
643 | unsigned char fsx_pad[12]; | ||
644 | }; | ||
645 | |||
646 | /* | ||
647 | * Flags for the fsx_xflags field | ||
648 | */ | ||
649 | #define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ | ||
650 | #define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ | ||
651 | #define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ | ||
652 | #define FS_XFLAG_APPEND 0x00000010 /* all writes append */ | ||
653 | #define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ | ||
654 | #define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ | ||
655 | #define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ | ||
656 | #define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ | ||
657 | #define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ | ||
658 | #define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ | ||
659 | #define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ | ||
660 | #define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ | ||
661 | #define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ | ||
662 | #define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ | ||
663 | #define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ | ||
664 | #endif /* !defined(FS_IOC_FSGETXATTR) */ | ||
665 | |||
666 | #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR | ||
667 | #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR | ||
668 | |||
622 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | 669 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) |
623 | /* | 670 | /* |
624 | * ioctl commands in 32 bit emulation | 671 | * ioctl commands in 32 bit emulation |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 5e872fd40e5e..2b0cb84255eb 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/mount.h> | 14 | #include <linux/mount.h> |
15 | #include <linux/file.h> | 15 | #include <linux/file.h> |
16 | #include <linux/random.h> | 16 | #include <linux/random.h> |
17 | #include <linux/quotaops.h> | ||
17 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
18 | #include "ext4_jbd2.h" | 19 | #include "ext4_jbd2.h" |
19 | #include "ext4.h" | 20 | #include "ext4.h" |
@@ -202,6 +203,238 @@ static int uuid_is_zero(__u8 u[16]) | |||
202 | return 1; | 203 | return 1; |
203 | } | 204 | } |
204 | 205 | ||
206 | static int ext4_ioctl_setflags(struct inode *inode, | ||
207 | unsigned int flags) | ||
208 | { | ||
209 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
210 | handle_t *handle = NULL; | ||
211 | int err = EPERM, migrate = 0; | ||
212 | struct ext4_iloc iloc; | ||
213 | unsigned int oldflags, mask, i; | ||
214 | unsigned int jflag; | ||
215 | |||
216 | /* Is it quota file? Do not allow user to mess with it */ | ||
217 | if (IS_NOQUOTA(inode)) | ||
218 | goto flags_out; | ||
219 | |||
220 | oldflags = ei->i_flags; | ||
221 | |||
222 | /* The JOURNAL_DATA flag is modifiable only by root */ | ||
223 | jflag = flags & EXT4_JOURNAL_DATA_FL; | ||
224 | |||
225 | /* | ||
226 | * The IMMUTABLE and APPEND_ONLY flags can only be changed by | ||
227 | * the relevant capability. | ||
228 | * | ||
229 | * This test looks nicer. Thanks to Pauline Middelink | ||
230 | */ | ||
231 | if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { | ||
232 | if (!capable(CAP_LINUX_IMMUTABLE)) | ||
233 | goto flags_out; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * The JOURNAL_DATA flag can only be changed by | ||
238 | * the relevant capability. | ||
239 | */ | ||
240 | if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { | ||
241 | if (!capable(CAP_SYS_RESOURCE)) | ||
242 | goto flags_out; | ||
243 | } | ||
244 | if ((flags ^ oldflags) & EXT4_EXTENTS_FL) | ||
245 | migrate = 1; | ||
246 | |||
247 | if (flags & EXT4_EOFBLOCKS_FL) { | ||
248 | /* we don't support adding EOFBLOCKS flag */ | ||
249 | if (!(oldflags & EXT4_EOFBLOCKS_FL)) { | ||
250 | err = -EOPNOTSUPP; | ||
251 | goto flags_out; | ||
252 | } | ||
253 | } else if (oldflags & EXT4_EOFBLOCKS_FL) | ||
254 | ext4_truncate(inode); | ||
255 | |||
256 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); | ||
257 | if (IS_ERR(handle)) { | ||
258 | err = PTR_ERR(handle); | ||
259 | goto flags_out; | ||
260 | } | ||
261 | if (IS_SYNC(inode)) | ||
262 | ext4_handle_sync(handle); | ||
263 | err = ext4_reserve_inode_write(handle, inode, &iloc); | ||
264 | if (err) | ||
265 | goto flags_err; | ||
266 | |||
267 | for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { | ||
268 | if (!(mask & EXT4_FL_USER_MODIFIABLE)) | ||
269 | continue; | ||
270 | if (mask & flags) | ||
271 | ext4_set_inode_flag(inode, i); | ||
272 | else | ||
273 | ext4_clear_inode_flag(inode, i); | ||
274 | } | ||
275 | |||
276 | ext4_set_inode_flags(inode); | ||
277 | inode->i_ctime = ext4_current_time(inode); | ||
278 | |||
279 | err = ext4_mark_iloc_dirty(handle, inode, &iloc); | ||
280 | flags_err: | ||
281 | ext4_journal_stop(handle); | ||
282 | if (err) | ||
283 | goto flags_out; | ||
284 | |||
285 | if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) | ||
286 | err = ext4_change_inode_journal_flag(inode, jflag); | ||
287 | if (err) | ||
288 | goto flags_out; | ||
289 | if (migrate) { | ||
290 | if (flags & EXT4_EXTENTS_FL) | ||
291 | err = ext4_ext_migrate(inode); | ||
292 | else | ||
293 | err = ext4_ind_migrate(inode); | ||
294 | } | ||
295 | |||
296 | flags_out: | ||
297 | return err; | ||
298 | } | ||
299 | |||
300 | #ifdef CONFIG_QUOTA | ||
301 | static int ext4_ioctl_setproject(struct file *filp, __u32 projid) | ||
302 | { | ||
303 | struct inode *inode = file_inode(filp); | ||
304 | struct super_block *sb = inode->i_sb; | ||
305 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
306 | int err, rc; | ||
307 | handle_t *handle; | ||
308 | kprojid_t kprojid; | ||
309 | struct ext4_iloc iloc; | ||
310 | struct ext4_inode *raw_inode; | ||
311 | |||
312 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
313 | EXT4_FEATURE_RO_COMPAT_PROJECT)) { | ||
314 | if (projid != EXT4_DEF_PROJID) | ||
315 | return -EOPNOTSUPP; | ||
316 | else | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE) | ||
321 | return -EOPNOTSUPP; | ||
322 | |||
323 | kprojid = make_kprojid(&init_user_ns, (projid_t)projid); | ||
324 | |||
325 | if (projid_eq(kprojid, EXT4_I(inode)->i_projid)) | ||
326 | return 0; | ||
327 | |||
328 | err = mnt_want_write_file(filp); | ||
329 | if (err) | ||
330 | return err; | ||
331 | |||
332 | err = -EPERM; | ||
333 | mutex_lock(&inode->i_mutex); | ||
334 | /* Is it quota file? Do not allow user to mess with it */ | ||
335 | if (IS_NOQUOTA(inode)) | ||
336 | goto out_unlock; | ||
337 | |||
338 | err = ext4_get_inode_loc(inode, &iloc); | ||
339 | if (err) | ||
340 | goto out_unlock; | ||
341 | |||
342 | raw_inode = ext4_raw_inode(&iloc); | ||
343 | if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) { | ||
344 | err = -EOVERFLOW; | ||
345 | brelse(iloc.bh); | ||
346 | goto out_unlock; | ||
347 | } | ||
348 | brelse(iloc.bh); | ||
349 | |||
350 | dquot_initialize(inode); | ||
351 | |||
352 | handle = ext4_journal_start(inode, EXT4_HT_QUOTA, | ||
353 | EXT4_QUOTA_INIT_BLOCKS(sb) + | ||
354 | EXT4_QUOTA_DEL_BLOCKS(sb) + 3); | ||
355 | if (IS_ERR(handle)) { | ||
356 | err = PTR_ERR(handle); | ||
357 | goto out_unlock; | ||
358 | } | ||
359 | |||
360 | err = ext4_reserve_inode_write(handle, inode, &iloc); | ||
361 | if (err) | ||
362 | goto out_stop; | ||
363 | |||
364 | if (sb_has_quota_limits_enabled(sb, PRJQUOTA)) { | ||
365 | struct dquot *transfer_to[MAXQUOTAS] = { }; | ||
366 | |||
367 | transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); | ||
368 | if (transfer_to[PRJQUOTA]) { | ||
369 | err = __dquot_transfer(inode, transfer_to); | ||
370 | dqput(transfer_to[PRJQUOTA]); | ||
371 | if (err) | ||
372 | goto out_dirty; | ||
373 | } | ||
374 | } | ||
375 | EXT4_I(inode)->i_projid = kprojid; | ||
376 | inode->i_ctime = ext4_current_time(inode); | ||
377 | out_dirty: | ||
378 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); | ||
379 | if (!err) | ||
380 | err = rc; | ||
381 | out_stop: | ||
382 | ext4_journal_stop(handle); | ||
383 | out_unlock: | ||
384 | mutex_unlock(&inode->i_mutex); | ||
385 | mnt_drop_write_file(filp); | ||
386 | return err; | ||
387 | } | ||
388 | #else | ||
389 | static int ext4_ioctl_setproject(struct file *filp, __u32 projid) | ||
390 | { | ||
391 | if (projid != EXT4_DEF_PROJID) | ||
392 | return -EOPNOTSUPP; | ||
393 | return 0; | ||
394 | } | ||
395 | #endif | ||
396 | |||
397 | /* Transfer internal flags to xflags */ | ||
398 | static inline __u32 ext4_iflags_to_xflags(unsigned long iflags) | ||
399 | { | ||
400 | __u32 xflags = 0; | ||
401 | |||
402 | if (iflags & EXT4_SYNC_FL) | ||
403 | xflags |= FS_XFLAG_SYNC; | ||
404 | if (iflags & EXT4_IMMUTABLE_FL) | ||
405 | xflags |= FS_XFLAG_IMMUTABLE; | ||
406 | if (iflags & EXT4_APPEND_FL) | ||
407 | xflags |= FS_XFLAG_APPEND; | ||
408 | if (iflags & EXT4_NODUMP_FL) | ||
409 | xflags |= FS_XFLAG_NODUMP; | ||
410 | if (iflags & EXT4_NOATIME_FL) | ||
411 | xflags |= FS_XFLAG_NOATIME; | ||
412 | if (iflags & EXT4_PROJINHERIT_FL) | ||
413 | xflags |= FS_XFLAG_PROJINHERIT; | ||
414 | return xflags; | ||
415 | } | ||
416 | |||
417 | /* Transfer xflags flags to internal */ | ||
418 | static inline unsigned long ext4_xflags_to_iflags(__u32 xflags) | ||
419 | { | ||
420 | unsigned long iflags = 0; | ||
421 | |||
422 | if (xflags & FS_XFLAG_SYNC) | ||
423 | iflags |= EXT4_SYNC_FL; | ||
424 | if (xflags & FS_XFLAG_IMMUTABLE) | ||
425 | iflags |= EXT4_IMMUTABLE_FL; | ||
426 | if (xflags & FS_XFLAG_APPEND) | ||
427 | iflags |= EXT4_APPEND_FL; | ||
428 | if (xflags & FS_XFLAG_NODUMP) | ||
429 | iflags |= EXT4_NODUMP_FL; | ||
430 | if (xflags & FS_XFLAG_NOATIME) | ||
431 | iflags |= EXT4_NOATIME_FL; | ||
432 | if (xflags & FS_XFLAG_PROJINHERIT) | ||
433 | iflags |= EXT4_PROJINHERIT_FL; | ||
434 | |||
435 | return iflags; | ||
436 | } | ||
437 | |||
205 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 438 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
206 | { | 439 | { |
207 | struct inode *inode = file_inode(filp); | 440 | struct inode *inode = file_inode(filp); |
@@ -217,11 +450,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
217 | flags = ei->i_flags & EXT4_FL_USER_VISIBLE; | 450 | flags = ei->i_flags & EXT4_FL_USER_VISIBLE; |
218 | return put_user(flags, (int __user *) arg); | 451 | return put_user(flags, (int __user *) arg); |
219 | case EXT4_IOC_SETFLAGS: { | 452 | case EXT4_IOC_SETFLAGS: { |
220 | handle_t *handle = NULL; | 453 | int err; |
221 | int err, migrate = 0; | ||
222 | struct ext4_iloc iloc; | ||
223 | unsigned int oldflags, mask, i; | ||
224 | unsigned int jflag; | ||
225 | 454 | ||
226 | if (!inode_owner_or_capable(inode)) | 455 | if (!inode_owner_or_capable(inode)) |
227 | return -EACCES; | 456 | return -EACCES; |
@@ -235,89 +464,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
235 | 464 | ||
236 | flags = ext4_mask_flags(inode->i_mode, flags); | 465 | flags = ext4_mask_flags(inode->i_mode, flags); |
237 | 466 | ||
238 | err = -EPERM; | ||
239 | mutex_lock(&inode->i_mutex); | 467 | mutex_lock(&inode->i_mutex); |
240 | /* Is it quota file? Do not allow user to mess with it */ | 468 | err = ext4_ioctl_setflags(inode, flags); |
241 | if (IS_NOQUOTA(inode)) | ||
242 | goto flags_out; | ||
243 | |||
244 | oldflags = ei->i_flags; | ||
245 | |||
246 | /* The JOURNAL_DATA flag is modifiable only by root */ | ||
247 | jflag = flags & EXT4_JOURNAL_DATA_FL; | ||
248 | |||
249 | /* | ||
250 | * The IMMUTABLE and APPEND_ONLY flags can only be changed by | ||
251 | * the relevant capability. | ||
252 | * | ||
253 | * This test looks nicer. Thanks to Pauline Middelink | ||
254 | */ | ||
255 | if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { | ||
256 | if (!capable(CAP_LINUX_IMMUTABLE)) | ||
257 | goto flags_out; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * The JOURNAL_DATA flag can only be changed by | ||
262 | * the relevant capability. | ||
263 | */ | ||
264 | if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { | ||
265 | if (!capable(CAP_SYS_RESOURCE)) | ||
266 | goto flags_out; | ||
267 | } | ||
268 | if ((flags ^ oldflags) & EXT4_EXTENTS_FL) | ||
269 | migrate = 1; | ||
270 | |||
271 | if (flags & EXT4_EOFBLOCKS_FL) { | ||
272 | /* we don't support adding EOFBLOCKS flag */ | ||
273 | if (!(oldflags & EXT4_EOFBLOCKS_FL)) { | ||
274 | err = -EOPNOTSUPP; | ||
275 | goto flags_out; | ||
276 | } | ||
277 | } else if (oldflags & EXT4_EOFBLOCKS_FL) | ||
278 | ext4_truncate(inode); | ||
279 | |||
280 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); | ||
281 | if (IS_ERR(handle)) { | ||
282 | err = PTR_ERR(handle); | ||
283 | goto flags_out; | ||
284 | } | ||
285 | if (IS_SYNC(inode)) | ||
286 | ext4_handle_sync(handle); | ||
287 | err = ext4_reserve_inode_write(handle, inode, &iloc); | ||
288 | if (err) | ||
289 | goto flags_err; | ||
290 | |||
291 | for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { | ||
292 | if (!(mask & EXT4_FL_USER_MODIFIABLE)) | ||
293 | continue; | ||
294 | if (mask & flags) | ||
295 | ext4_set_inode_flag(inode, i); | ||
296 | else | ||
297 | ext4_clear_inode_flag(inode, i); | ||
298 | } | ||
299 | |||
300 | ext4_set_inode_flags(inode); | ||
301 | inode->i_ctime = ext4_current_time(inode); | ||
302 | |||
303 | err = ext4_mark_iloc_dirty(handle, inode, &iloc); | ||
304 | flags_err: | ||
305 | ext4_journal_stop(handle); | ||
306 | if (err) | ||
307 | goto flags_out; | ||
308 | |||
309 | if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) | ||
310 | err = ext4_change_inode_journal_flag(inode, jflag); | ||
311 | if (err) | ||
312 | goto flags_out; | ||
313 | if (migrate) { | ||
314 | if (flags & EXT4_EXTENTS_FL) | ||
315 | err = ext4_ext_migrate(inode); | ||
316 | else | ||
317 | err = ext4_ind_migrate(inode); | ||
318 | } | ||
319 | |||
320 | flags_out: | ||
321 | mutex_unlock(&inode->i_mutex); | 469 | mutex_unlock(&inode->i_mutex); |
322 | mnt_drop_write_file(filp); | 470 | mnt_drop_write_file(filp); |
323 | return err; | 471 | return err; |
@@ -689,6 +837,60 @@ encryption_policy_out: | |||
689 | return -EOPNOTSUPP; | 837 | return -EOPNOTSUPP; |
690 | #endif | 838 | #endif |
691 | } | 839 | } |
840 | case EXT4_IOC_FSGETXATTR: | ||
841 | { | ||
842 | struct fsxattr fa; | ||
843 | |||
844 | memset(&fa, 0, sizeof(struct fsxattr)); | ||
845 | ext4_get_inode_flags(ei); | ||
846 | fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE); | ||
847 | |||
848 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
849 | EXT4_FEATURE_RO_COMPAT_PROJECT)) { | ||
850 | fa.fsx_projid = (__u32)from_kprojid(&init_user_ns, | ||
851 | EXT4_I(inode)->i_projid); | ||
852 | } | ||
853 | |||
854 | if (copy_to_user((struct fsxattr __user *)arg, | ||
855 | &fa, sizeof(fa))) | ||
856 | return -EFAULT; | ||
857 | return 0; | ||
858 | } | ||
859 | case EXT4_IOC_FSSETXATTR: | ||
860 | { | ||
861 | struct fsxattr fa; | ||
862 | int err; | ||
863 | |||
864 | if (copy_from_user(&fa, (struct fsxattr __user *)arg, | ||
865 | sizeof(fa))) | ||
866 | return -EFAULT; | ||
867 | |||
868 | /* Make sure caller has proper permission */ | ||
869 | if (!inode_owner_or_capable(inode)) | ||
870 | return -EACCES; | ||
871 | |||
872 | err = mnt_want_write_file(filp); | ||
873 | if (err) | ||
874 | return err; | ||
875 | |||
876 | flags = ext4_xflags_to_iflags(fa.fsx_xflags); | ||
877 | flags = ext4_mask_flags(inode->i_mode, flags); | ||
878 | |||
879 | mutex_lock(&inode->i_mutex); | ||
880 | flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) | | ||
881 | (flags & EXT4_FL_XFLAG_VISIBLE); | ||
882 | err = ext4_ioctl_setflags(inode, flags); | ||
883 | mutex_unlock(&inode->i_mutex); | ||
884 | mnt_drop_write_file(filp); | ||
885 | if (err) | ||
886 | return err; | ||
887 | |||
888 | err = ext4_ioctl_setproject(filp, fa.fsx_projid); | ||
889 | if (err) | ||
890 | return err; | ||
891 | |||
892 | return 0; | ||
893 | } | ||
692 | default: | 894 | default: |
693 | return -ENOTTY; | 895 | return -ENOTTY; |
694 | } | 896 | } |