Blame view

fs/reiserfs/ioctl.c 5.38 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
   */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
4
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
  #include <linux/fs.h>
42a74f206   Dave Hansen   [PATCH] r/o bind ...
6
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
  #include <linux/reiserfs_fs.h>
  #include <linux/time.h>
  #include <asm/uaccess.h>
  #include <linux/pagemap.h>
52b499c43   David Howells   [PATCH] BLOCK: Mo...
11
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  /*
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
14
15
16
17
18
19
20
   * reiserfs_ioctl - handler for ioctl for inode
   * supported commands:
   *  1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
   *                           and prevent packing file (argument arg has to be non-zero)
   *  2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
   *  3) That's all for a while ...
   */
205cb37b8   Frederic Weisbecker   kill-the-bkl/reis...
21
  long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  {
205cb37b8   Frederic Weisbecker   kill-the-bkl/reis...
23
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  	unsigned int flags;
42a74f206   Dave Hansen   [PATCH] r/o bind ...
25
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
27
  	reiserfs_write_lock(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  	switch (cmd) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
29
30
31
  	case REISERFS_IOC_UNPACK:
  		if (S_ISREG(inode->i_mode)) {
  			if (arg)
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
32
  				err = reiserfs_unpack(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  		} else
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
34
35
36
37
38
39
  			err = -ENOTTY;
  		break;
  		/*
  		 * following two cases are taken from fs/ext2/ioctl.c by Remy
  		 * Card (card@masi.ibp.fr)
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  	case REISERFS_IOC_GETFLAGS:
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
41
42
43
44
  		if (!reiserfs_attrs(inode->i_sb)) {
  			err = -ENOTTY;
  			break;
  		}
869eb76e7   Jeff Mahoney   [PATCH] reiserfs:...
45

bd4c625c0   Linus Torvalds   reiserfs: run scr...
46
47
  		flags = REISERFS_I(inode)->i_attrs;
  		i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
48
49
  		err = put_user(flags, (int __user *)arg);
  		break;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
50
  	case REISERFS_IOC_SETFLAGS:{
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
51
52
53
54
  			if (!reiserfs_attrs(inode->i_sb)) {
  				err = -ENOTTY;
  				break;
  			}
869eb76e7   Jeff Mahoney   [PATCH] reiserfs:...
55

a561be710   Al Viro   switch a bunch of...
56
  			err = mnt_want_write_file(filp);
42a74f206   Dave Hansen   [PATCH] r/o bind ...
57
  			if (err)
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
58
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

2e1496707   Serge E. Hallyn   userns: rename is...
60
  			if (!inode_owner_or_capable(inode)) {
42a74f206   Dave Hansen   [PATCH] r/o bind ...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  				err = -EPERM;
  				goto setflags_out;
  			}
  			if (get_user(flags, (int __user *)arg)) {
  				err = -EFAULT;
  				goto setflags_out;
  			}
  			/*
  			 * Is it quota file? Do not allow user to mess with it
  			 */
  			if (IS_NOQUOTA(inode)) {
  				err = -EPERM;
  				goto setflags_out;
  			}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
75
76
77
  			if (((flags ^ REISERFS_I(inode)->
  			      i_attrs) & (REISERFS_IMMUTABLE_FL |
  					  REISERFS_APPEND_FL))
42a74f206   Dave Hansen   [PATCH] r/o bind ...
78
79
80
81
  			    && !capable(CAP_LINUX_IMMUTABLE)) {
  				err = -EPERM;
  				goto setflags_out;
  			}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
82
83
  			if ((flags & REISERFS_NOTAIL_FL) &&
  			    S_ISREG(inode->i_mode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  				int result;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
85
  				result = reiserfs_unpack(inode, filp);
42a74f206   Dave Hansen   [PATCH] r/o bind ...
86
87
88
89
  				if (result) {
  					err = result;
  					goto setflags_out;
  				}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
90
91
92
93
94
  			}
  			sd_attrs_to_i_attrs(flags, inode);
  			REISERFS_I(inode)->i_attrs = flags;
  			inode->i_ctime = CURRENT_TIME_SEC;
  			mark_inode_dirty(inode);
42a74f206   Dave Hansen   [PATCH] r/o bind ...
95
  setflags_out:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
96
  			mnt_drop_write_file(filp);
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
97
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  	case REISERFS_IOC_GETVERSION:
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
100
101
  		err = put_user(inode->i_generation, (int __user *)arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	case REISERFS_IOC_SETVERSION:
2e1496707   Serge E. Hallyn   userns: rename is...
103
  		if (!inode_owner_or_capable(inode)) {
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
104
105
  			err = -EPERM;
  			break;
e0baec1b6   Jiri Slaby   reiserfs: Fix unr...
106
  		}
a561be710   Al Viro   switch a bunch of...
107
  		err = mnt_want_write_file(filp);
42a74f206   Dave Hansen   [PATCH] r/o bind ...
108
  		if (err)
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
109
  			break;
42a74f206   Dave Hansen   [PATCH] r/o bind ...
110
111
112
113
  		if (get_user(inode->i_generation, (int __user *)arg)) {
  			err = -EFAULT;
  			goto setversion_out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  		inode->i_ctime = CURRENT_TIME_SEC;
  		mark_inode_dirty(inode);
42a74f206   Dave Hansen   [PATCH] r/o bind ...
116
  setversion_out:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
117
  		mnt_drop_write_file(filp);
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
118
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  	default:
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
120
  		err = -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  	}
ac78a0789   Frederic Weisbecker   kill-the-bkl/reis...
122
123
124
125
  
  	reiserfs_write_unlock(inode->i_sb);
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  }
52b499c43   David Howells   [PATCH] BLOCK: Mo...
127
128
129
130
  #ifdef CONFIG_COMPAT
  long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
  				unsigned long arg)
  {
52b499c43   David Howells   [PATCH] BLOCK: Mo...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  	/* These are just misnamed, they actually get/put from/to user an int */
  	switch (cmd) {
  	case REISERFS_IOC32_UNPACK:
  		cmd = REISERFS_IOC_UNPACK;
  		break;
  	case REISERFS_IOC32_GETFLAGS:
  		cmd = REISERFS_IOC_GETFLAGS;
  		break;
  	case REISERFS_IOC32_SETFLAGS:
  		cmd = REISERFS_IOC_SETFLAGS;
  		break;
  	case REISERFS_IOC32_GETVERSION:
  		cmd = REISERFS_IOC_GETVERSION;
  		break;
  	case REISERFS_IOC32_SETVERSION:
  		cmd = REISERFS_IOC_SETVERSION;
  		break;
  	default:
  		return -ENOIOCTLCMD;
  	}
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
151

205cb37b8   Frederic Weisbecker   kill-the-bkl/reis...
152
  	return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
52b499c43   David Howells   [PATCH] BLOCK: Mo...
153
154
  }
  #endif
ba9d8cec6   Vladimir Saveliev   reiserfs: convert...
155
156
  int reiserfs_commit_write(struct file *f, struct page *page,
  			  unsigned from, unsigned to);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  /*
  ** reiserfs_unpack
  ** Function try to convert tail from direct item into indirect.
  ** It set up nopack attribute in the REISERFS_I(inode)->nopack
  */
d5dee5c39   Jan Kara   reiserfs: unpack ...
162
  int reiserfs_unpack(struct inode *inode, struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
164
  	int retval = 0;
9d8117e72   Frederic Weisbecker   reiserfs: fix unw...
165
  	int depth;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  	int index;
  	struct page *page;
  	struct address_space *mapping;
  	unsigned long write_from;
  	unsigned long blocksize = inode->i_sb->s_blocksize;
  
  	if (inode->i_size == 0) {
  		REISERFS_I(inode)->i_flags |= i_nopack_mask;
  		return 0;
  	}
  	/* ioctl already done */
  	if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
  		return 0;
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
180

9d8117e72   Frederic Weisbecker   reiserfs: fix unw...
181
  	depth = reiserfs_write_lock_once(inode->i_sb);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
182

da905873e   Frederic Weisbecker   reiserfs: fix ino...
183
184
  	/* we need to make sure nobody is changing the file size beneath us */
  	reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
185
186
187
188
189
190
191
192
  	write_from = inode->i_size & (blocksize - 1);
  	/* if we are on a block boundary, we are already unpacked.  */
  	if (write_from == 0) {
  		REISERFS_I(inode)->i_flags |= i_nopack_mask;
  		goto out;
  	}
  
  	/* we unpack by finding the page with the tail, and calling
ebdec241d   Christoph Hellwig   fs: kill block_pr...
193
  	 ** __reiserfs_write_begin on that page.  This will force a
bd4c625c0   Linus Torvalds   reiserfs: run scr...
194
195
196
197
198
199
200
201
202
  	 ** reiserfs_get_block to unpack the tail for us.
  	 */
  	index = inode->i_size >> PAGE_CACHE_SHIFT;
  	mapping = inode->i_mapping;
  	page = grab_cache_page(mapping, index);
  	retval = -ENOMEM;
  	if (!page) {
  		goto out;
  	}
ebdec241d   Christoph Hellwig   fs: kill block_pr...
203
  	retval = __reiserfs_write_begin(page, write_from, 0);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
204
205
206
207
208
  	if (retval)
  		goto out_unlock;
  
  	/* conversion can change page contents, must flush */
  	flush_dcache_page(page);
ba9d8cec6   Vladimir Saveliev   reiserfs: convert...
209
  	retval = reiserfs_commit_write(NULL, page, write_from, write_from);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	REISERFS_I(inode)->i_flags |= i_nopack_mask;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
211
212
213
214
215
216
  
        out_unlock:
  	unlock_page(page);
  	page_cache_release(page);
  
        out:
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
217
  	mutex_unlock(&inode->i_mutex);
9d8117e72   Frederic Weisbecker   reiserfs: fix unw...
218
  	reiserfs_write_unlock_once(inode->i_sb, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
219
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  }