FreeBSD/Linux Kernel Cross Reference
sys/fs/ext3/ioctl.c
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
10 #include <linux/fs.h>
11 #include <linux/jbd.h>
12 #include <linux/ext3_fs.h>
13 #include <linux/ext3_jbd.h>
14 #include <linux/sched.h>
15 #include <asm/uaccess.h>
16
17
18 int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
19 unsigned long arg)
20 {
21 unsigned int flags;
22
23 ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
24
25 switch (cmd) {
26 case EXT3_IOC_GETFLAGS:
27 flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE;
28 return put_user(flags, (int *) arg);
29 case EXT3_IOC_SETFLAGS: {
30 handle_t *handle = NULL;
31 int err;
32 struct ext3_iloc iloc;
33 unsigned int oldflags;
34 unsigned int jflag;
35
36 if (IS_RDONLY(inode))
37 return -EROFS;
38
39 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
40 return -EACCES;
41
42 if (get_user(flags, (int *) arg))
43 return -EFAULT;
44
45 oldflags = inode->u.ext3_i.i_flags;
46
47 /* The JOURNAL_DATA flag is modifiable only by root */
48 jflag = flags & EXT3_JOURNAL_DATA_FL;
49
50 /*
51 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
52 * the relevant capability.
53 *
54 * This test looks nicer. Thanks to Pauline Middelink
55 */
56 if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
57 if (!capable(CAP_LINUX_IMMUTABLE))
58 return -EPERM;
59 }
60
61 /*
62 * The JOURNAL_DATA flag can only be changed by
63 * the relevant capability.
64 */
65 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
66 if (!capable(CAP_SYS_RESOURCE))
67 return -EPERM;
68 }
69
70
71 handle = ext3_journal_start(inode, 1);
72 if (IS_ERR(handle))
73 return PTR_ERR(handle);
74 if (IS_SYNC(inode))
75 handle->h_sync = 1;
76 err = ext3_reserve_inode_write(handle, inode, &iloc);
77 if (err)
78 goto flags_err;
79
80 flags = flags & EXT3_FL_USER_MODIFIABLE;
81 flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
82 inode->u.ext3_i.i_flags = flags;
83
84 ext3_set_inode_flags(inode);
85 inode->i_ctime = CURRENT_TIME;
86
87 err = ext3_mark_iloc_dirty(handle, inode, &iloc);
88 flags_err:
89 ext3_journal_stop(handle, inode);
90 if (err)
91 return err;
92
93 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
94 err = ext3_change_inode_journal_flag(inode, jflag);
95 return err;
96 }
97 case EXT3_IOC_GETVERSION:
98 case EXT3_IOC_GETVERSION_OLD:
99 return put_user(inode->i_generation, (int *) arg);
100 case EXT3_IOC_SETVERSION:
101 case EXT3_IOC_SETVERSION_OLD: {
102 handle_t *handle;
103 struct ext3_iloc iloc;
104 __u32 generation;
105 int err;
106
107 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
108 return -EPERM;
109 if (IS_RDONLY(inode))
110 return -EROFS;
111 if (get_user(generation, (int *) arg))
112 return -EFAULT;
113
114 handle = ext3_journal_start(inode, 1);
115 if (IS_ERR(handle))
116 return PTR_ERR(handle);
117 err = ext3_reserve_inode_write(handle, inode, &iloc);
118 if (err)
119 return err;
120
121 inode->i_ctime = CURRENT_TIME;
122 inode->i_generation = generation;
123
124 err = ext3_mark_iloc_dirty(handle, inode, &iloc);
125 ext3_journal_stop(handle, inode);
126 return err;
127 }
128 #ifdef CONFIG_JBD_DEBUG
129 case EXT3_IOC_WAIT_FOR_READONLY:
130 /*
131 * This is racy - by the time we're woken up and running,
132 * the superblock could be released. And the module could
133 * have been unloaded. So sue me.
134 *
135 * Returns 1 if it slept, else zero.
136 */
137 {
138 struct super_block *sb = inode->i_sb;
139 DECLARE_WAITQUEUE(wait, current);
140 int ret = 0;
141
142 set_current_state(TASK_INTERRUPTIBLE);
143 add_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait);
144 if (timer_pending(&sb->u.ext3_sb.turn_ro_timer)) {
145 schedule();
146 ret = 1;
147 }
148 remove_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait);
149 return ret;
150 }
151 #endif
152 default:
153 return -ENOTTY;
154 }
155 }
Cache object: 228a0c8018beca062ab1c861113b9ba6
|