ioctl.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/fs/jfs/ioctl.c
  4. *
  5. * Copyright (C) 2006 Herbert Poetzl
  6. * adapted from Remy Card's ext2/ioctl.c
  7. */
  8. #include <linux/fs.h>
  9. #include <linux/ctype.h>
  10. #include <linux/capability.h>
  11. #include <linux/mount.h>
  12. #include <linux/time.h>
  13. #include <linux/sched.h>
  14. #include <linux/blkdev.h>
  15. #include <asm/current.h>
  16. #include <linux/uaccess.h>
  17. #include "jfs_filsys.h"
  18. #include "jfs_debug.h"
  19. #include "jfs_incore.h"
  20. #include "jfs_dinode.h"
  21. #include "jfs_inode.h"
  22. #include "jfs_dmap.h"
  23. #include "jfs_discard.h"
  24. static struct {
  25. long jfs_flag;
  26. long ext2_flag;
  27. } jfs_map[] = {
  28. {JFS_NOATIME_FL, FS_NOATIME_FL},
  29. {JFS_DIRSYNC_FL, FS_DIRSYNC_FL},
  30. {JFS_SYNC_FL, FS_SYNC_FL},
  31. {JFS_SECRM_FL, FS_SECRM_FL},
  32. {JFS_UNRM_FL, FS_UNRM_FL},
  33. {JFS_APPEND_FL, FS_APPEND_FL},
  34. {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL},
  35. {0, 0},
  36. };
  37. static long jfs_map_ext2(unsigned long flags, int from)
  38. {
  39. int index=0;
  40. long mapped=0;
  41. while (jfs_map[index].jfs_flag) {
  42. if (from) {
  43. if (jfs_map[index].ext2_flag & flags)
  44. mapped |= jfs_map[index].jfs_flag;
  45. } else {
  46. if (jfs_map[index].jfs_flag & flags)
  47. mapped |= jfs_map[index].ext2_flag;
  48. }
  49. index++;
  50. }
  51. return mapped;
  52. }
  53. long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  54. {
  55. struct inode *inode = file_inode(filp);
  56. struct jfs_inode_info *jfs_inode = JFS_IP(inode);
  57. unsigned int flags;
  58. switch (cmd) {
  59. case JFS_IOC_GETFLAGS:
  60. flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
  61. flags = jfs_map_ext2(flags, 0);
  62. return put_user(flags, (int __user *) arg);
  63. case JFS_IOC_SETFLAGS: {
  64. unsigned int oldflags;
  65. int err;
  66. err = mnt_want_write_file(filp);
  67. if (err)
  68. return err;
  69. if (!inode_owner_or_capable(inode)) {
  70. err = -EACCES;
  71. goto setflags_out;
  72. }
  73. if (get_user(flags, (int __user *) arg)) {
  74. err = -EFAULT;
  75. goto setflags_out;
  76. }
  77. flags = jfs_map_ext2(flags, 1);
  78. if (!S_ISDIR(inode->i_mode))
  79. flags &= ~JFS_DIRSYNC_FL;
  80. /* Is it quota file? Do not allow user to mess with it */
  81. if (IS_NOQUOTA(inode)) {
  82. err = -EPERM;
  83. goto setflags_out;
  84. }
  85. /* Lock against other parallel changes of flags */
  86. inode_lock(inode);
  87. oldflags = jfs_inode->mode2;
  88. /*
  89. * The IMMUTABLE and APPEND_ONLY flags can only be changed by
  90. * the relevant capability.
  91. */
  92. if ((oldflags & JFS_IMMUTABLE_FL) ||
  93. ((flags ^ oldflags) &
  94. (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
  95. if (!capable(CAP_LINUX_IMMUTABLE)) {
  96. inode_unlock(inode);
  97. err = -EPERM;
  98. goto setflags_out;
  99. }
  100. }
  101. flags = flags & JFS_FL_USER_MODIFIABLE;
  102. flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
  103. jfs_inode->mode2 = flags;
  104. jfs_set_inode_flags(inode);
  105. inode_unlock(inode);
  106. inode->i_ctime = current_time(inode);
  107. mark_inode_dirty(inode);
  108. setflags_out:
  109. mnt_drop_write_file(filp);
  110. return err;
  111. }
  112. case FITRIM:
  113. {
  114. struct super_block *sb = inode->i_sb;
  115. struct request_queue *q = bdev_get_queue(sb->s_bdev);
  116. struct fstrim_range range;
  117. s64 ret = 0;
  118. if (!capable(CAP_SYS_ADMIN))
  119. return -EPERM;
  120. if (!blk_queue_discard(q)) {
  121. jfs_warn("FITRIM not supported on device");
  122. return -EOPNOTSUPP;
  123. }
  124. if (copy_from_user(&range, (struct fstrim_range __user *)arg,
  125. sizeof(range)))
  126. return -EFAULT;
  127. range.minlen = max_t(unsigned int, range.minlen,
  128. q->limits.discard_granularity);
  129. ret = jfs_ioc_trim(inode, &range);
  130. if (ret < 0)
  131. return ret;
  132. if (copy_to_user((struct fstrim_range __user *)arg, &range,
  133. sizeof(range)))
  134. return -EFAULT;
  135. return 0;
  136. }
  137. default:
  138. return -ENOTTY;
  139. }
  140. }
  141. #ifdef CONFIG_COMPAT
  142. long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  143. {
  144. /* While these ioctl numbers defined with 'long' and have different
  145. * numbers than the 64bit ABI,
  146. * the actual implementation only deals with ints and is compatible.
  147. */
  148. switch (cmd) {
  149. case JFS_IOC_GETFLAGS32:
  150. cmd = JFS_IOC_GETFLAGS;
  151. break;
  152. case JFS_IOC_SETFLAGS32:
  153. cmd = JFS_IOC_SETFLAGS;
  154. break;
  155. }
  156. return jfs_ioctl(filp, cmd, arg);
  157. }
  158. #endif