]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README | |
3 | */ | |
4 | ||
5 | #include <linux/fs.h> | |
6 | #include <linux/reiserfs_fs.h> | |
7 | #include <linux/time.h> | |
8 | #include <asm/uaccess.h> | |
9 | #include <linux/pagemap.h> | |
10 | #include <linux/smp_lock.h> | |
11 | ||
bd4c625c | 12 | static int reiserfs_unpack(struct inode *inode, struct file *filp); |
1da177e4 LT |
13 | |
14 | /* | |
15 | ** reiserfs_ioctl - handler for ioctl for inode | |
16 | ** supported commands: | |
17 | ** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect | |
18 | ** and prevent packing file (argument arg has to be non-zero) | |
19 | ** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION | |
20 | ** 3) That's all for a while ... | |
21 | */ | |
bd4c625c LT |
22 | int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
23 | unsigned long arg) | |
1da177e4 LT |
24 | { |
25 | unsigned int flags; | |
26 | ||
27 | switch (cmd) { | |
bd4c625c LT |
28 | case REISERFS_IOC_UNPACK: |
29 | if (S_ISREG(inode->i_mode)) { | |
30 | if (arg) | |
31 | return reiserfs_unpack(inode, filp); | |
1da177e4 LT |
32 | else |
33 | return 0; | |
34 | } else | |
35 | return -ENOTTY; | |
bd4c625c LT |
36 | /* following two cases are taken from fs/ext2/ioctl.c by Remy |
37 | Card (card@masi.ibp.fr) */ | |
1da177e4 | 38 | case REISERFS_IOC_GETFLAGS: |
bd4c625c | 39 | if (!reiserfs_attrs(inode->i_sb)) |
869eb76e JM |
40 | return -ENOTTY; |
41 | ||
bd4c625c LT |
42 | flags = REISERFS_I(inode)->i_attrs; |
43 | i_attrs_to_sd_attrs(inode, (__u16 *) & flags); | |
44 | return put_user(flags, (int __user *)arg); | |
45 | case REISERFS_IOC_SETFLAGS:{ | |
46 | if (!reiserfs_attrs(inode->i_sb)) | |
47 | return -ENOTTY; | |
869eb76e | 48 | |
bd4c625c LT |
49 | if (IS_RDONLY(inode)) |
50 | return -EROFS; | |
1da177e4 | 51 | |
bd4c625c LT |
52 | if ((current->fsuid != inode->i_uid) |
53 | && !capable(CAP_FOWNER)) | |
54 | return -EPERM; | |
1da177e4 | 55 | |
bd4c625c LT |
56 | if (get_user(flags, (int __user *)arg)) |
57 | return -EFAULT; | |
1da177e4 | 58 | |
bd4c625c LT |
59 | if (((flags ^ REISERFS_I(inode)-> |
60 | i_attrs) & (REISERFS_IMMUTABLE_FL | | |
61 | REISERFS_APPEND_FL)) | |
62 | && !capable(CAP_LINUX_IMMUTABLE)) | |
63 | return -EPERM; | |
64 | ||
65 | if ((flags & REISERFS_NOTAIL_FL) && | |
66 | S_ISREG(inode->i_mode)) { | |
1da177e4 LT |
67 | int result; |
68 | ||
bd4c625c LT |
69 | result = reiserfs_unpack(inode, filp); |
70 | if (result) | |
1da177e4 | 71 | return result; |
bd4c625c LT |
72 | } |
73 | sd_attrs_to_i_attrs(flags, inode); | |
74 | REISERFS_I(inode)->i_attrs = flags; | |
75 | inode->i_ctime = CURRENT_TIME_SEC; | |
76 | mark_inode_dirty(inode); | |
77 | return 0; | |
1da177e4 | 78 | } |
1da177e4 | 79 | case REISERFS_IOC_GETVERSION: |
bd4c625c | 80 | return put_user(inode->i_generation, (int __user *)arg); |
1da177e4 LT |
81 | case REISERFS_IOC_SETVERSION: |
82 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | |
83 | return -EPERM; | |
84 | if (IS_RDONLY(inode)) | |
85 | return -EROFS; | |
bd4c625c LT |
86 | if (get_user(inode->i_generation, (int __user *)arg)) |
87 | return -EFAULT; | |
1da177e4 LT |
88 | inode->i_ctime = CURRENT_TIME_SEC; |
89 | mark_inode_dirty(inode); | |
90 | return 0; | |
91 | default: | |
92 | return -ENOTTY; | |
93 | } | |
94 | } | |
95 | ||
96 | /* | |
97 | ** reiserfs_unpack | |
98 | ** Function try to convert tail from direct item into indirect. | |
99 | ** It set up nopack attribute in the REISERFS_I(inode)->nopack | |
100 | */ | |
bd4c625c | 101 | static int reiserfs_unpack(struct inode *inode, struct file *filp) |
1da177e4 | 102 | { |
bd4c625c LT |
103 | int retval = 0; |
104 | int index; | |
105 | struct page *page; | |
106 | struct address_space *mapping; | |
107 | unsigned long write_from; | |
108 | unsigned long blocksize = inode->i_sb->s_blocksize; | |
109 | ||
110 | if (inode->i_size == 0) { | |
111 | REISERFS_I(inode)->i_flags |= i_nopack_mask; | |
112 | return 0; | |
113 | } | |
114 | /* ioctl already done */ | |
115 | if (REISERFS_I(inode)->i_flags & i_nopack_mask) { | |
116 | return 0; | |
117 | } | |
118 | reiserfs_write_lock(inode->i_sb); | |
119 | ||
120 | /* we need to make sure nobody is changing the file size beneath | |
121 | ** us | |
122 | */ | |
1b1dcc1b | 123 | mutex_lock(&inode->i_mutex); |
bd4c625c LT |
124 | |
125 | write_from = inode->i_size & (blocksize - 1); | |
126 | /* if we are on a block boundary, we are already unpacked. */ | |
127 | if (write_from == 0) { | |
128 | REISERFS_I(inode)->i_flags |= i_nopack_mask; | |
129 | goto out; | |
130 | } | |
131 | ||
132 | /* we unpack by finding the page with the tail, and calling | |
133 | ** reiserfs_prepare_write on that page. This will force a | |
134 | ** reiserfs_get_block to unpack the tail for us. | |
135 | */ | |
136 | index = inode->i_size >> PAGE_CACHE_SHIFT; | |
137 | mapping = inode->i_mapping; | |
138 | page = grab_cache_page(mapping, index); | |
139 | retval = -ENOMEM; | |
140 | if (!page) { | |
141 | goto out; | |
142 | } | |
143 | retval = | |
144 | mapping->a_ops->prepare_write(NULL, page, write_from, write_from); | |
145 | if (retval) | |
146 | goto out_unlock; | |
147 | ||
148 | /* conversion can change page contents, must flush */ | |
149 | flush_dcache_page(page); | |
150 | retval = | |
151 | mapping->a_ops->commit_write(NULL, page, write_from, write_from); | |
1da177e4 | 152 | REISERFS_I(inode)->i_flags |= i_nopack_mask; |
bd4c625c LT |
153 | |
154 | out_unlock: | |
155 | unlock_page(page); | |
156 | page_cache_release(page); | |
157 | ||
158 | out: | |
1b1dcc1b | 159 | mutex_unlock(&inode->i_mutex); |
bd4c625c LT |
160 | reiserfs_write_unlock(inode->i_sb); |
161 | return retval; | |
1da177e4 | 162 | } |