ioctl.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * linux/fs/ext3/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. #include <linux/fs.h>
  10. #include <linux/jbd.h>
  11. #include <linux/ext3_fs.h>
  12. #include <linux/ext3_jbd.h>
  13. #include <linux/time.h>
  14. #include <asm/uaccess.h>
  15. int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
  16. unsigned long arg)
  17. {
  18. struct ext3_inode_info *ei = EXT3_I(inode);
  19. unsigned int flags;
  20. unsigned short rsv_window_size;
  21. ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
  22. switch (cmd) {
  23. case EXT3_IOC_GETFLAGS:
  24. flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
  25. return put_user(flags, (int __user *) arg);
  26. case EXT3_IOC_SETFLAGS: {
  27. handle_t *handle = NULL;
  28. int err;
  29. struct ext3_iloc iloc;
  30. unsigned int oldflags;
  31. unsigned int jflag;
  32. if (IS_RDONLY(inode))
  33. return -EROFS;
  34. if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
  35. return -EACCES;
  36. if (get_user(flags, (int __user *) arg))
  37. return -EFAULT;
  38. if (!S_ISDIR(inode->i_mode))
  39. flags &= ~EXT3_DIRSYNC_FL;
  40. oldflags = ei->i_flags;
  41. /* The JOURNAL_DATA flag is modifiable only by root */
  42. jflag = flags & EXT3_JOURNAL_DATA_FL;
  43. /*
  44. * The IMMUTABLE and APPEND_ONLY flags can only be changed by
  45. * the relevant capability.
  46. *
  47. * This test looks nicer. Thanks to Pauline Middelink
  48. */
  49. if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
  50. if (!capable(CAP_LINUX_IMMUTABLE))
  51. return -EPERM;
  52. }
  53. /*
  54. * The JOURNAL_DATA flag can only be changed by
  55. * the relevant capability.
  56. */
  57. if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
  58. if (!capable(CAP_SYS_RESOURCE))
  59. return -EPERM;
  60. }
  61. handle = ext3_journal_start(inode, 1);
  62. if (IS_ERR(handle))
  63. return PTR_ERR(handle);
  64. if (IS_SYNC(inode))
  65. handle->h_sync = 1;
  66. err = ext3_reserve_inode_write(handle, inode, &iloc);
  67. if (err)
  68. goto flags_err;
  69. flags = flags & EXT3_FL_USER_MODIFIABLE;
  70. flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
  71. ei->i_flags = flags;
  72. ext3_set_inode_flags(inode);
  73. inode->i_ctime = CURRENT_TIME_SEC;
  74. err = ext3_mark_iloc_dirty(handle, inode, &iloc);
  75. flags_err:
  76. ext3_journal_stop(handle);
  77. if (err)
  78. return err;
  79. if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
  80. err = ext3_change_inode_journal_flag(inode, jflag);
  81. return err;
  82. }
  83. case EXT3_IOC_GETVERSION:
  84. case EXT3_IOC_GETVERSION_OLD:
  85. return put_user(inode->i_generation, (int __user *) arg);
  86. case EXT3_IOC_SETVERSION:
  87. case EXT3_IOC_SETVERSION_OLD: {
  88. handle_t *handle;
  89. struct ext3_iloc iloc;
  90. __u32 generation;
  91. int err;
  92. if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
  93. return -EPERM;
  94. if (IS_RDONLY(inode))
  95. return -EROFS;
  96. if (get_user(generation, (int __user *) arg))
  97. return -EFAULT;
  98. handle = ext3_journal_start(inode, 1);
  99. if (IS_ERR(handle))
  100. return PTR_ERR(handle);
  101. err = ext3_reserve_inode_write(handle, inode, &iloc);
  102. if (err == 0) {
  103. inode->i_ctime = CURRENT_TIME_SEC;
  104. inode->i_generation = generation;
  105. err = ext3_mark_iloc_dirty(handle, inode, &iloc);
  106. }
  107. ext3_journal_stop(handle);
  108. return err;
  109. }
  110. #ifdef CONFIG_JBD_DEBUG
  111. case EXT3_IOC_WAIT_FOR_READONLY:
  112. /*
  113. * This is racy - by the time we're woken up and running,
  114. * the superblock could be released. And the module could
  115. * have been unloaded. So sue me.
  116. *
  117. * Returns 1 if it slept, else zero.
  118. */
  119. {
  120. struct super_block *sb = inode->i_sb;
  121. DECLARE_WAITQUEUE(wait, current);
  122. int ret = 0;
  123. set_current_state(TASK_INTERRUPTIBLE);
  124. add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait);
  125. if (timer_pending(&EXT3_SB(sb)->turn_ro_timer)) {
  126. schedule();
  127. ret = 1;
  128. }
  129. remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait);
  130. return ret;
  131. }
  132. #endif
  133. case EXT3_IOC_GETRSVSZ:
  134. if (test_opt(inode->i_sb, RESERVATION)
  135. && S_ISREG(inode->i_mode)
  136. && ei->i_block_alloc_info) {
  137. rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
  138. return put_user(rsv_window_size, (int __user *)arg);
  139. }
  140. return -ENOTTY;
  141. case EXT3_IOC_SETRSVSZ: {
  142. if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
  143. return -ENOTTY;
  144. if (IS_RDONLY(inode))
  145. return -EROFS;
  146. if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
  147. return -EACCES;
  148. if (get_user(rsv_window_size, (int __user *)arg))
  149. return -EFAULT;
  150. if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS)
  151. rsv_window_size = EXT3_MAX_RESERVE_BLOCKS;
  152. /*
  153. * need to allocate reservation structure for this inode
  154. * before set the window size
  155. */
  156. down(&ei->truncate_sem);
  157. if (!ei->i_block_alloc_info)
  158. ext3_init_block_alloc_info(inode);
  159. if (ei->i_block_alloc_info){
  160. struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
  161. rsv->rsv_goal_size = rsv_window_size;
  162. }
  163. up(&ei->truncate_sem);
  164. return 0;
  165. }
  166. case EXT3_IOC_GROUP_EXTEND: {
  167. unsigned long n_blocks_count;
  168. struct super_block *sb = inode->i_sb;
  169. int err;
  170. if (!capable(CAP_SYS_RESOURCE))
  171. return -EPERM;
  172. if (IS_RDONLY(inode))
  173. return -EROFS;
  174. if (get_user(n_blocks_count, (__u32 __user *)arg))
  175. return -EFAULT;
  176. err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count);
  177. journal_lock_updates(EXT3_SB(sb)->s_journal);
  178. journal_flush(EXT3_SB(sb)->s_journal);
  179. journal_unlock_updates(EXT3_SB(sb)->s_journal);
  180. return err;
  181. }
  182. case EXT3_IOC_GROUP_ADD: {
  183. struct ext3_new_group_data input;
  184. struct super_block *sb = inode->i_sb;
  185. int err;
  186. if (!capable(CAP_SYS_RESOURCE))
  187. return -EPERM;
  188. if (IS_RDONLY(inode))
  189. return -EROFS;
  190. if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg,
  191. sizeof(input)))
  192. return -EFAULT;
  193. err = ext3_group_add(sb, &input);
  194. journal_lock_updates(EXT3_SB(sb)->s_journal);
  195. journal_flush(EXT3_SB(sb)->s_journal);
  196. journal_unlock_updates(EXT3_SB(sb)->s_journal);
  197. return err;
  198. }
  199. default:
  200. return -ENOTTY;
  201. }
  202. }