~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ext4/ioctl.c

Version: ~ [ linux-5.11 ] ~ [ linux-5.10.17 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.99 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.176 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.221 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.257 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.257 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/fs/ext4/ioctl.c
  3  *
  4  * Copyright (C) 1993, 1994, 1995
  5  * Remy Card (card@masi.ibp.fr)
  6  * Laboratoire MASI - Institut Blaise Pascal
  7  * Universite Pierre et Marie Curie (Paris VI)
  8  */
  9 
 10 #include <linux/fs.h>
 11 #include <linux/jbd2.h>
 12 #include <linux/capability.h>
 13 #include <linux/time.h>
 14 #include <linux/compat.h>
 15 #include <linux/mount.h>
 16 #include <linux/file.h>
 17 #include <asm/uaccess.h>
 18 #include "ext4_jbd2.h"
 19 #include "ext4.h"
 20 
 21 #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
 22 
 23 /**
 24  * Swap memory between @a and @b for @len bytes.
 25  *
 26  * @a:          pointer to first memory area
 27  * @b:          pointer to second memory area
 28  * @len:        number of bytes to swap
 29  *
 30  */
 31 static void memswap(void *a, void *b, size_t len)
 32 {
 33         unsigned char *ap, *bp;
 34         unsigned char tmp;
 35 
 36         ap = (unsigned char *)a;
 37         bp = (unsigned char *)b;
 38         while (len-- > 0) {
 39                 tmp = *ap;
 40                 *ap = *bp;
 41                 *bp = tmp;
 42                 ap++;
 43                 bp++;
 44         }
 45 }
 46 
 47 /**
 48  * Swap i_data and associated attributes between @inode1 and @inode2.
 49  * This function is used for the primary swap between inode1 and inode2
 50  * and also to revert this primary swap in case of errors.
 51  *
 52  * Therefore you have to make sure, that calling this method twice
 53  * will revert all changes.
 54  *
 55  * @inode1:     pointer to first inode
 56  * @inode2:     pointer to second inode
 57  */
 58 static void swap_inode_data(struct inode *inode1, struct inode *inode2)
 59 {
 60         loff_t isize;
 61         struct ext4_inode_info *ei1;
 62         struct ext4_inode_info *ei2;
 63 
 64         ei1 = EXT4_I(inode1);
 65         ei2 = EXT4_I(inode2);
 66 
 67         memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags));
 68         memswap(&inode1->i_version, &inode2->i_version,
 69                   sizeof(inode1->i_version));
 70         memswap(&inode1->i_blocks, &inode2->i_blocks,
 71                   sizeof(inode1->i_blocks));
 72         memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes));
 73         memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime));
 74         memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime));
 75 
 76         memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
 77         memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
 78         memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
 79         ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS);
 80         ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS);
 81         ext4_es_lru_del(inode1);
 82         ext4_es_lru_del(inode2);
 83 
 84         isize = i_size_read(inode1);
 85         i_size_write(inode1, i_size_read(inode2));
 86         i_size_write(inode2, isize);
 87 }
 88 
 89 /**
 90  * Swap the information from the given @inode and the inode
 91  * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
 92  * important fields of the inodes.
 93  *
 94  * @sb:         the super block of the filesystem
 95  * @inode:      the inode to swap with EXT4_BOOT_LOADER_INO
 96  *
 97  */
 98 static long swap_inode_boot_loader(struct super_block *sb,
 99                                 struct inode *inode)
100 {
101         handle_t *handle;
102         int err;
103         struct inode *inode_bl;
104         struct ext4_inode_info *ei_bl;
105         struct ext4_sb_info *sbi = EXT4_SB(sb);
106 
107         if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode))
108                 return -EINVAL;
109 
110         if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
111                 return -EPERM;
112 
113         inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
114         if (IS_ERR(inode_bl))
115                 return PTR_ERR(inode_bl);
116         ei_bl = EXT4_I(inode_bl);
117 
118         filemap_flush(inode->i_mapping);
119         filemap_flush(inode_bl->i_mapping);
120 
121         /* Protect orig inodes against a truncate and make sure,
122          * that only 1 swap_inode_boot_loader is running. */
123         lock_two_nondirectories(inode, inode_bl);
124 
125         truncate_inode_pages(&inode->i_data, 0);
126         truncate_inode_pages(&inode_bl->i_data, 0);
127 
128         /* Wait for all existing dio workers */
129         ext4_inode_block_unlocked_dio(inode);
130         ext4_inode_block_unlocked_dio(inode_bl);
131         inode_dio_wait(inode);
132         inode_dio_wait(inode_bl);
133 
134         handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
135         if (IS_ERR(handle)) {
136                 err = -EINVAL;
137                 goto journal_err_out;
138         }
139 
140         /* Protect extent tree against block allocations via delalloc */
141         ext4_double_down_write_data_sem(inode, inode_bl);
142 
143         if (inode_bl->i_nlink == 0) {
144                 /* this inode has never been used as a BOOT_LOADER */
145                 set_nlink(inode_bl, 1);
146                 i_uid_write(inode_bl, 0);
147                 i_gid_write(inode_bl, 0);
148                 inode_bl->i_flags = 0;
149                 ei_bl->i_flags = 0;
150                 inode_bl->i_version = 1;
151                 i_size_write(inode_bl, 0);
152                 inode_bl->i_mode = S_IFREG;
153                 if (EXT4_HAS_INCOMPAT_FEATURE(sb,
154                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) {
155                         ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS);
156                         ext4_ext_tree_init(handle, inode_bl);
157                 } else
158                         memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
159         }
160 
161         swap_inode_data(inode, inode_bl);
162 
163         inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode);
164 
165         spin_lock(&sbi->s_next_gen_lock);
166         inode->i_generation = sbi->s_next_generation++;
167         inode_bl->i_generation = sbi->s_next_generation++;
168         spin_unlock(&sbi->s_next_gen_lock);
169 
170         ext4_discard_preallocations(inode);
171 
172         err = ext4_mark_inode_dirty(handle, inode);
173         if (err < 0) {
174                 ext4_warning(inode->i_sb,
175                         "couldn't mark inode #%lu dirty (err %d)",
176                         inode->i_ino, err);
177                 /* Revert all changes: */
178                 swap_inode_data(inode, inode_bl);
179         } else {
180                 err = ext4_mark_inode_dirty(handle, inode_bl);
181                 if (err < 0) {
182                         ext4_warning(inode_bl->i_sb,
183                                 "couldn't mark inode #%lu dirty (err %d)",
184                                 inode_bl->i_ino, err);
185                         /* Revert all changes: */
186                         swap_inode_data(inode, inode_bl);
187                         ext4_mark_inode_dirty(handle, inode);
188                 }
189         }
190         ext4_journal_stop(handle);
191         ext4_double_up_write_data_sem(inode, inode_bl);
192 
193 journal_err_out:
194         ext4_inode_resume_unlocked_dio(inode);
195         ext4_inode_resume_unlocked_dio(inode_bl);
196         unlock_two_nondirectories(inode, inode_bl);
197         iput(inode_bl);
198         return err;
199 }
200 
201 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
202 {
203         struct inode *inode = file_inode(filp);
204         struct super_block *sb = inode->i_sb;
205         struct ext4_inode_info *ei = EXT4_I(inode);
206         unsigned int flags;
207 
208         ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
209 
210         switch (cmd) {
211         case EXT4_IOC_GETFLAGS:
212                 ext4_get_inode_flags(ei);
213                 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
214                 return put_user(flags, (int __user *) arg);
215         case EXT4_IOC_SETFLAGS: {
216                 handle_t *handle = NULL;
217                 int err, migrate = 0;
218                 struct ext4_iloc iloc;
219                 unsigned int oldflags, mask, i;
220                 unsigned int jflag;
221 
222                 if (!inode_owner_or_capable(inode))
223                         return -EACCES;
224 
225                 if (get_user(flags, (int __user *) arg))
226                         return -EFAULT;
227 
228                 err = mnt_want_write_file(filp);
229                 if (err)
230                         return err;
231 
232                 flags = ext4_mask_flags(inode->i_mode, flags);
233 
234                 err = -EPERM;
235                 mutex_lock(&inode->i_mutex);
236                 /* Is it quota file? Do not allow user to mess with it */
237                 if (IS_NOQUOTA(inode))
238                         goto flags_out;
239 
240                 oldflags = ei->i_flags;
241 
242                 /* The JOURNAL_DATA flag is modifiable only by root */
243                 jflag = flags & EXT4_JOURNAL_DATA_FL;
244 
245                 /*
246                  * The IMMUTABLE and APPEND_ONLY flags can only be changed by
247                  * the relevant capability.
248                  *
249                  * This test looks nicer. Thanks to Pauline Middelink
250                  */
251                 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
252                         if (!capable(CAP_LINUX_IMMUTABLE))
253                                 goto flags_out;
254                 }
255 
256                 /*
257                  * The JOURNAL_DATA flag can only be changed by
258                  * the relevant capability.
259                  */
260                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
261                         if (!capable(CAP_SYS_RESOURCE))
262                                 goto flags_out;
263                 }
264                 if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
265                         migrate = 1;
266 
267                 if (flags & EXT4_EOFBLOCKS_FL) {
268                         /* we don't support adding EOFBLOCKS flag */
269                         if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
270                                 err = -EOPNOTSUPP;
271                                 goto flags_out;
272                         }
273                 } else if (oldflags & EXT4_EOFBLOCKS_FL)
274                         ext4_truncate(inode);
275 
276                 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
277                 if (IS_ERR(handle)) {
278                         err = PTR_ERR(handle);
279                         goto flags_out;
280                 }
281                 if (IS_SYNC(inode))
282                         ext4_handle_sync(handle);
283                 err = ext4_reserve_inode_write(handle, inode, &iloc);
284                 if (err)
285                         goto flags_err;
286 
287                 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
288                         if (!(mask & EXT4_FL_USER_MODIFIABLE))
289                                 continue;
290                         if (mask & flags)
291                                 ext4_set_inode_flag(inode, i);
292                         else
293                                 ext4_clear_inode_flag(inode, i);
294                 }
295 
296                 ext4_set_inode_flags(inode);
297                 inode->i_ctime = ext4_current_time(inode);
298 
299                 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
300 flags_err:
301                 ext4_journal_stop(handle);
302                 if (err)
303                         goto flags_out;
304 
305                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
306                         err = ext4_change_inode_journal_flag(inode, jflag);
307                 if (err)
308                         goto flags_out;
309                 if (migrate) {
310                         if (flags & EXT4_EXTENTS_FL)
311                                 err = ext4_ext_migrate(inode);
312                         else
313                                 err = ext4_ind_migrate(inode);
314                 }
315 
316 flags_out:
317                 mutex_unlock(&inode->i_mutex);
318                 mnt_drop_write_file(filp);
319                 return err;
320         }
321         case EXT4_IOC_GETVERSION:
322         case EXT4_IOC_GETVERSION_OLD:
323                 return put_user(inode->i_generation, (int __user *) arg);
324         case EXT4_IOC_SETVERSION:
325         case EXT4_IOC_SETVERSION_OLD: {
326                 handle_t *handle;
327                 struct ext4_iloc iloc;
328                 __u32 generation;
329                 int err;
330 
331                 if (!inode_owner_or_capable(inode))
332                         return -EPERM;
333 
334                 if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
335                                 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
336                         ext4_warning(sb, "Setting inode version is not "
337                                      "supported with metadata_csum enabled.");
338                         return -ENOTTY;
339                 }
340 
341                 err = mnt_want_write_file(filp);
342                 if (err)
343                         return err;
344                 if (get_user(generation, (int __user *) arg)) {
345                         err = -EFAULT;
346                         goto setversion_out;
347                 }
348 
349                 mutex_lock(&inode->i_mutex);
350                 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
351                 if (IS_ERR(handle)) {
352                         err = PTR_ERR(handle);
353                         goto unlock_out;
354                 }
355                 err = ext4_reserve_inode_write(handle, inode, &iloc);
356                 if (err == 0) {
357                         inode->i_ctime = ext4_current_time(inode);
358                         inode->i_generation = generation;
359                         err = ext4_mark_iloc_dirty(handle, inode, &iloc);
360                 }
361                 ext4_journal_stop(handle);
362 
363 unlock_out:
364                 mutex_unlock(&inode->i_mutex);
365 setversion_out:
366                 mnt_drop_write_file(filp);
367                 return err;
368         }
369         case EXT4_IOC_GROUP_EXTEND: {
370                 ext4_fsblk_t n_blocks_count;
371                 int err, err2=0;
372 
373                 err = ext4_resize_begin(sb);
374                 if (err)
375                         return err;
376 
377                 if (get_user(n_blocks_count, (__u32 __user *)arg)) {
378                         err = -EFAULT;
379                         goto group_extend_out;
380                 }
381 
382                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
383                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
384                         ext4_msg(sb, KERN_ERR,
385                                  "Online resizing not supported with bigalloc");
386                         err = -EOPNOTSUPP;
387                         goto group_extend_out;
388                 }
389 
390                 err = mnt_want_write_file(filp);
391                 if (err)
392                         goto group_extend_out;
393 
394                 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
395                 if (EXT4_SB(sb)->s_journal) {
396                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
397                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
398                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
399                 }
400                 if (err == 0)
401                         err = err2;
402                 mnt_drop_write_file(filp);
403 group_extend_out:
404                 ext4_resize_end(sb);
405                 return err;
406         }
407 
408         case EXT4_IOC_MOVE_EXT: {
409                 struct move_extent me;
410                 struct fd donor;
411                 int err;
412 
413                 if (!(filp->f_mode & FMODE_READ) ||
414                     !(filp->f_mode & FMODE_WRITE))
415                         return -EBADF;
416 
417                 if (copy_from_user(&me,
418                         (struct move_extent __user *)arg, sizeof(me)))
419                         return -EFAULT;
420                 me.moved_len = 0;
421 
422                 donor = fdget(me.donor_fd);
423                 if (!donor.file)
424                         return -EBADF;
425 
426                 if (!(donor.file->f_mode & FMODE_WRITE)) {
427                         err = -EBADF;
428                         goto mext_out;
429                 }
430 
431                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
432                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
433                         ext4_msg(sb, KERN_ERR,
434                                  "Online defrag not supported with bigalloc");
435                         err = -EOPNOTSUPP;
436                         goto mext_out;
437                 }
438 
439                 err = mnt_want_write_file(filp);
440                 if (err)
441                         goto mext_out;
442 
443                 err = ext4_move_extents(filp, donor.file, me.orig_start,
444                                         me.donor_start, me.len, &me.moved_len);
445                 mnt_drop_write_file(filp);
446 
447                 if (copy_to_user((struct move_extent __user *)arg,
448                                  &me, sizeof(me)))
449                         err = -EFAULT;
450 mext_out:
451                 fdput(donor);
452                 return err;
453         }
454 
455         case EXT4_IOC_GROUP_ADD: {
456                 struct ext4_new_group_data input;
457                 int err, err2=0;
458 
459                 err = ext4_resize_begin(sb);
460                 if (err)
461                         return err;
462 
463                 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
464                                 sizeof(input))) {
465                         err = -EFAULT;
466                         goto group_add_out;
467                 }
468 
469                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
470                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
471                         ext4_msg(sb, KERN_ERR,
472                                  "Online resizing not supported with bigalloc");
473                         err = -EOPNOTSUPP;
474                         goto group_add_out;
475                 }
476 
477                 err = mnt_want_write_file(filp);
478                 if (err)
479                         goto group_add_out;
480 
481                 err = ext4_group_add(sb, &input);
482                 if (EXT4_SB(sb)->s_journal) {
483                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
484                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
485                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
486                 }
487                 if (err == 0)
488                         err = err2;
489                 mnt_drop_write_file(filp);
490                 if (!err && ext4_has_group_desc_csum(sb) &&
491                     test_opt(sb, INIT_INODE_TABLE))
492                         err = ext4_register_li_request(sb, input.group);
493 group_add_out:
494                 ext4_resize_end(sb);
495                 return err;
496         }
497 
498         case EXT4_IOC_MIGRATE:
499         {
500                 int err;
501                 if (!inode_owner_or_capable(inode))
502                         return -EACCES;
503 
504                 err = mnt_want_write_file(filp);
505                 if (err)
506                         return err;
507                 /*
508                  * inode_mutex prevent write and truncate on the file.
509                  * Read still goes through. We take i_data_sem in
510                  * ext4_ext_swap_inode_data before we switch the
511                  * inode format to prevent read.
512                  */
513                 mutex_lock(&(inode->i_mutex));
514                 err = ext4_ext_migrate(inode);
515                 mutex_unlock(&(inode->i_mutex));
516                 mnt_drop_write_file(filp);
517                 return err;
518         }
519 
520         case EXT4_IOC_ALLOC_DA_BLKS:
521         {
522                 int err;
523                 if (!inode_owner_or_capable(inode))
524                         return -EACCES;
525 
526                 err = mnt_want_write_file(filp);
527                 if (err)
528                         return err;
529                 err = ext4_alloc_da_blocks(inode);
530                 mnt_drop_write_file(filp);
531                 return err;
532         }
533 
534         case EXT4_IOC_SWAP_BOOT:
535                 if (!(filp->f_mode & FMODE_WRITE))
536                         return -EBADF;
537                 return swap_inode_boot_loader(sb, inode);
538 
539         case EXT4_IOC_RESIZE_FS: {
540                 ext4_fsblk_t n_blocks_count;
541                 int err = 0, err2 = 0;
542                 ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
543 
544                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
545                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
546                         ext4_msg(sb, KERN_ERR,
547                                  "Online resizing not (yet) supported with bigalloc");
548                         return -EOPNOTSUPP;
549                 }
550 
551                 if (copy_from_user(&n_blocks_count, (__u64 __user *)arg,
552                                    sizeof(__u64))) {
553                         return -EFAULT;
554                 }
555 
556                 err = ext4_resize_begin(sb);
557                 if (err)
558                         return err;
559 
560                 err = mnt_want_write_file(filp);
561                 if (err)
562                         goto resizefs_out;
563 
564                 err = ext4_resize_fs(sb, n_blocks_count);
565                 if (EXT4_SB(sb)->s_journal) {
566                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
567                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
568                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
569                 }
570                 if (err == 0)
571                         err = err2;
572                 mnt_drop_write_file(filp);
573                 if (!err && (o_group > EXT4_SB(sb)->s_groups_count) &&
574                     ext4_has_group_desc_csum(sb) &&
575                     test_opt(sb, INIT_INODE_TABLE))
576                         err = ext4_register_li_request(sb, o_group);
577 
578 resizefs_out:
579                 ext4_resize_end(sb);
580                 return err;
581         }
582 
583         case FITRIM:
584         {
585                 struct request_queue *q = bdev_get_queue(sb->s_bdev);
586                 struct fstrim_range range;
587                 int ret = 0;
588 
589                 if (!capable(CAP_SYS_ADMIN))
590                         return -EPERM;
591 
592                 if (!blk_queue_discard(q))
593                         return -EOPNOTSUPP;
594 
595                 if (copy_from_user(&range, (struct fstrim_range __user *)arg,
596                     sizeof(range)))
597                         return -EFAULT;
598 
599                 range.minlen = max((unsigned int)range.minlen,
600                                    q->limits.discard_granularity);
601                 ret = ext4_trim_fs(sb, &range);
602                 if (ret < 0)
603                         return ret;
604 
605                 if (copy_to_user((struct fstrim_range __user *)arg, &range,
606                     sizeof(range)))
607                         return -EFAULT;
608 
609                 return 0;
610         }
611         case EXT4_IOC_PRECACHE_EXTENTS:
612                 return ext4_ext_precache(inode);
613 
614         default:
615                 return -ENOTTY;
616         }
617 }
618 
619 #ifdef CONFIG_COMPAT
620 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
621 {
622         /* These are just misnamed, they actually get/put from/to user an int */
623         switch (cmd) {
624         case EXT4_IOC32_GETFLAGS:
625                 cmd = EXT4_IOC_GETFLAGS;
626                 break;
627         case EXT4_IOC32_SETFLAGS:
628                 cmd = EXT4_IOC_SETFLAGS;
629                 break;
630         case EXT4_IOC32_GETVERSION:
631                 cmd = EXT4_IOC_GETVERSION;
632                 break;
633         case EXT4_IOC32_SETVERSION:
634                 cmd = EXT4_IOC_SETVERSION;
635                 break;
636         case EXT4_IOC32_GROUP_EXTEND:
637                 cmd = EXT4_IOC_GROUP_EXTEND;
638                 break;
639         case EXT4_IOC32_GETVERSION_OLD:
640                 cmd = EXT4_IOC_GETVERSION_OLD;
641                 break;
642         case EXT4_IOC32_SETVERSION_OLD:
643                 cmd = EXT4_IOC_SETVERSION_OLD;
644                 break;
645         case EXT4_IOC32_GETRSVSZ:
646                 cmd = EXT4_IOC_GETRSVSZ;
647                 break;
648         case EXT4_IOC32_SETRSVSZ:
649                 cmd = EXT4_IOC_SETRSVSZ;
650                 break;
651         case EXT4_IOC32_GROUP_ADD: {
652                 struct compat_ext4_new_group_input __user *uinput;
653                 struct ext4_new_group_input input;
654                 mm_segment_t old_fs;
655                 int err;
656 
657                 uinput = compat_ptr(arg);
658                 err = get_user(input.group, &uinput->group);
659                 err |= get_user(input.block_bitmap, &uinput->block_bitmap);
660                 err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
661                 err |= get_user(input.inode_table, &uinput->inode_table);
662                 err |= get_user(input.blocks_count, &uinput->blocks_count);
663                 err |= get_user(input.reserved_blocks,
664                                 &uinput->reserved_blocks);
665                 if (err)
666                         return -EFAULT;
667                 old_fs = get_fs();
668                 set_fs(KERNEL_DS);
669                 err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
670                                  (unsigned long) &input);
671                 set_fs(old_fs);
672                 return err;
673         }
674         case EXT4_IOC_MOVE_EXT:
675         case FITRIM:
676         case EXT4_IOC_RESIZE_FS:
677         case EXT4_IOC_PRECACHE_EXTENTS:
678                 break;
679         default:
680                 return -ENOIOCTLCMD;
681         }
682         return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
683 }
684 #endif
685 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp