Blame view
fs/reiserfs/ioctl.c
5.38 KB
1da177e4c
|
1 2 3 |
/* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ |
16f7e0fe2
|
4 |
#include <linux/capability.h> |
1da177e4c
|
5 |
#include <linux/fs.h> |
42a74f206
|
6 |
#include <linux/mount.h> |
f466c6fdb
|
7 |
#include "reiserfs.h" |
1da177e4c
|
8 9 10 |
#include <linux/time.h> #include <asm/uaccess.h> #include <linux/pagemap.h> |
52b499c43
|
11 |
#include <linux/compat.h> |
1da177e4c
|
12 |
|
1da177e4c
|
13 |
/* |
ac78a0789
|
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
|
21 |
long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1da177e4c
|
22 |
{ |
205cb37b8
|
23 |
struct inode *inode = filp->f_path.dentry->d_inode; |
1da177e4c
|
24 |
unsigned int flags; |
42a74f206
|
25 |
int err = 0; |
1da177e4c
|
26 |
|
ac78a0789
|
27 |
reiserfs_write_lock(inode->i_sb); |
1da177e4c
|
28 |
switch (cmd) { |
bd4c625c0
|
29 30 31 |
case REISERFS_IOC_UNPACK: if (S_ISREG(inode->i_mode)) { if (arg) |
ac78a0789
|
32 |
err = reiserfs_unpack(inode, filp); |
1da177e4c
|
33 |
} else |
ac78a0789
|
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
|
40 |
case REISERFS_IOC_GETFLAGS: |
ac78a0789
|
41 42 43 44 |
if (!reiserfs_attrs(inode->i_sb)) { err = -ENOTTY; break; } |
869eb76e7
|
45 |
|
bd4c625c0
|
46 47 |
flags = REISERFS_I(inode)->i_attrs; i_attrs_to_sd_attrs(inode, (__u16 *) & flags); |
ac78a0789
|
48 49 |
err = put_user(flags, (int __user *)arg); break; |
bd4c625c0
|
50 |
case REISERFS_IOC_SETFLAGS:{ |
ac78a0789
|
51 52 53 54 |
if (!reiserfs_attrs(inode->i_sb)) { err = -ENOTTY; break; } |
869eb76e7
|
55 |
|
a561be710
|
56 |
err = mnt_want_write_file(filp); |
42a74f206
|
57 |
if (err) |
ac78a0789
|
58 |
break; |
1da177e4c
|
59 |
|
2e1496707
|
60 |
if (!inode_owner_or_capable(inode)) { |
42a74f206
|
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
|
75 76 77 |
if (((flags ^ REISERFS_I(inode)-> i_attrs) & (REISERFS_IMMUTABLE_FL | REISERFS_APPEND_FL)) |
42a74f206
|
78 79 80 81 |
&& !capable(CAP_LINUX_IMMUTABLE)) { err = -EPERM; goto setflags_out; } |
bd4c625c0
|
82 83 |
if ((flags & REISERFS_NOTAIL_FL) && S_ISREG(inode->i_mode)) { |
1da177e4c
|
84 |
int result; |
bd4c625c0
|
85 |
result = reiserfs_unpack(inode, filp); |
42a74f206
|
86 87 88 89 |
if (result) { err = result; goto setflags_out; } |
bd4c625c0
|
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
|
95 |
setflags_out: |
2a79f17e4
|
96 |
mnt_drop_write_file(filp); |
ac78a0789
|
97 |
break; |
1da177e4c
|
98 |
} |
1da177e4c
|
99 |
case REISERFS_IOC_GETVERSION: |
ac78a0789
|
100 101 |
err = put_user(inode->i_generation, (int __user *)arg); break; |
1da177e4c
|
102 |
case REISERFS_IOC_SETVERSION: |
2e1496707
|
103 |
if (!inode_owner_or_capable(inode)) { |
ac78a0789
|
104 105 |
err = -EPERM; break; |
e0baec1b6
|
106 |
} |
a561be710
|
107 |
err = mnt_want_write_file(filp); |
42a74f206
|
108 |
if (err) |
ac78a0789
|
109 |
break; |
42a74f206
|
110 111 112 113 |
if (get_user(inode->i_generation, (int __user *)arg)) { err = -EFAULT; goto setversion_out; } |
1da177e4c
|
114 115 |
inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); |
42a74f206
|
116 |
setversion_out: |
2a79f17e4
|
117 |
mnt_drop_write_file(filp); |
ac78a0789
|
118 |
break; |
1da177e4c
|
119 |
default: |
ac78a0789
|
120 |
err = -ENOTTY; |
1da177e4c
|
121 |
} |
ac78a0789
|
122 123 124 125 |
reiserfs_write_unlock(inode->i_sb); return err; |
1da177e4c
|
126 |
} |
52b499c43
|
127 128 129 130 |
#ifdef CONFIG_COMPAT long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
52b499c43
|
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
|
151 |
|
205cb37b8
|
152 |
return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); |
52b499c43
|
153 154 |
} #endif |
ba9d8cec6
|
155 156 |
int reiserfs_commit_write(struct file *f, struct page *page, unsigned from, unsigned to); |
1da177e4c
|
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
|
162 |
int reiserfs_unpack(struct inode *inode, struct file *filp) |
1da177e4c
|
163 |
{ |
bd4c625c0
|
164 |
int retval = 0; |
9d8117e72
|
165 |
int depth; |
bd4c625c0
|
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
|
180 |
|
9d8117e72
|
181 |
depth = reiserfs_write_lock_once(inode->i_sb); |
bd4c625c0
|
182 |
|
da905873e
|
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
|
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
|
193 |
** __reiserfs_write_begin on that page. This will force a |
bd4c625c0
|
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
|
203 |
retval = __reiserfs_write_begin(page, write_from, 0); |
bd4c625c0
|
204 205 206 207 208 |
if (retval) goto out_unlock; /* conversion can change page contents, must flush */ flush_dcache_page(page); |
ba9d8cec6
|
209 |
retval = reiserfs_commit_write(NULL, page, write_from, write_from); |
1da177e4c
|
210 |
REISERFS_I(inode)->i_flags |= i_nopack_mask; |
bd4c625c0
|
211 212 213 214 215 216 |
out_unlock: unlock_page(page); page_cache_release(page); out: |
1b1dcc1b5
|
217 |
mutex_unlock(&inode->i_mutex); |
9d8117e72
|
218 |
reiserfs_write_unlock_once(inode->i_sb, depth); |
bd4c625c0
|
219 |
return retval; |
1da177e4c
|
220 |
} |