ioctl.c 4.0 KB

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