1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
3*4882a593Smuzhiyun */
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/capability.h>
6*4882a593Smuzhiyun #include <linux/fs.h>
7*4882a593Smuzhiyun #include <linux/mount.h>
8*4882a593Smuzhiyun #include "reiserfs.h"
9*4882a593Smuzhiyun #include <linux/time.h>
10*4882a593Smuzhiyun #include <linux/uaccess.h>
11*4882a593Smuzhiyun #include <linux/pagemap.h>
12*4882a593Smuzhiyun #include <linux/compat.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun * reiserfs_ioctl - handler for ioctl for inode
16*4882a593Smuzhiyun * supported commands:
17*4882a593Smuzhiyun * 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
18*4882a593Smuzhiyun * and prevent packing file (argument arg has t
19*4882a593Smuzhiyun * be non-zero)
20*4882a593Smuzhiyun * 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
21*4882a593Smuzhiyun * 3) That's all for a while ...
22*4882a593Smuzhiyun */
reiserfs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)23*4882a593Smuzhiyun long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun struct inode *inode = file_inode(filp);
26*4882a593Smuzhiyun unsigned int flags;
27*4882a593Smuzhiyun int err = 0;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun reiserfs_write_lock(inode->i_sb);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun switch (cmd) {
32*4882a593Smuzhiyun case REISERFS_IOC_UNPACK:
33*4882a593Smuzhiyun if (S_ISREG(inode->i_mode)) {
34*4882a593Smuzhiyun if (arg)
35*4882a593Smuzhiyun err = reiserfs_unpack(inode, filp);
36*4882a593Smuzhiyun } else
37*4882a593Smuzhiyun err = -ENOTTY;
38*4882a593Smuzhiyun break;
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun * following two cases are taken from fs/ext2/ioctl.c by Remy
41*4882a593Smuzhiyun * Card (card@masi.ibp.fr)
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun case REISERFS_IOC_GETFLAGS:
44*4882a593Smuzhiyun if (!reiserfs_attrs(inode->i_sb)) {
45*4882a593Smuzhiyun err = -ENOTTY;
46*4882a593Smuzhiyun break;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun flags = REISERFS_I(inode)->i_attrs;
50*4882a593Smuzhiyun err = put_user(flags, (int __user *)arg);
51*4882a593Smuzhiyun break;
52*4882a593Smuzhiyun case REISERFS_IOC_SETFLAGS:{
53*4882a593Smuzhiyun if (!reiserfs_attrs(inode->i_sb)) {
54*4882a593Smuzhiyun err = -ENOTTY;
55*4882a593Smuzhiyun break;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun err = mnt_want_write_file(filp);
59*4882a593Smuzhiyun if (err)
60*4882a593Smuzhiyun break;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (!inode_owner_or_capable(inode)) {
63*4882a593Smuzhiyun err = -EPERM;
64*4882a593Smuzhiyun goto setflags_out;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun if (get_user(flags, (int __user *)arg)) {
67*4882a593Smuzhiyun err = -EFAULT;
68*4882a593Smuzhiyun goto setflags_out;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Is it quota file? Do not allow user to mess with it
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun if (IS_NOQUOTA(inode)) {
74*4882a593Smuzhiyun err = -EPERM;
75*4882a593Smuzhiyun goto setflags_out;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun err = vfs_ioc_setflags_prepare(inode,
78*4882a593Smuzhiyun REISERFS_I(inode)->i_attrs,
79*4882a593Smuzhiyun flags);
80*4882a593Smuzhiyun if (err)
81*4882a593Smuzhiyun goto setflags_out;
82*4882a593Smuzhiyun if ((flags & REISERFS_NOTAIL_FL) &&
83*4882a593Smuzhiyun S_ISREG(inode->i_mode)) {
84*4882a593Smuzhiyun int result;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun result = reiserfs_unpack(inode, filp);
87*4882a593Smuzhiyun if (result) {
88*4882a593Smuzhiyun err = result;
89*4882a593Smuzhiyun goto setflags_out;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun sd_attrs_to_i_attrs(flags, inode);
93*4882a593Smuzhiyun REISERFS_I(inode)->i_attrs = flags;
94*4882a593Smuzhiyun inode->i_ctime = current_time(inode);
95*4882a593Smuzhiyun mark_inode_dirty(inode);
96*4882a593Smuzhiyun setflags_out:
97*4882a593Smuzhiyun mnt_drop_write_file(filp);
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun case REISERFS_IOC_GETVERSION:
101*4882a593Smuzhiyun err = put_user(inode->i_generation, (int __user *)arg);
102*4882a593Smuzhiyun break;
103*4882a593Smuzhiyun case REISERFS_IOC_SETVERSION:
104*4882a593Smuzhiyun if (!inode_owner_or_capable(inode)) {
105*4882a593Smuzhiyun err = -EPERM;
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun err = mnt_want_write_file(filp);
109*4882a593Smuzhiyun if (err)
110*4882a593Smuzhiyun break;
111*4882a593Smuzhiyun if (get_user(inode->i_generation, (int __user *)arg)) {
112*4882a593Smuzhiyun err = -EFAULT;
113*4882a593Smuzhiyun goto setversion_out;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun inode->i_ctime = current_time(inode);
116*4882a593Smuzhiyun mark_inode_dirty(inode);
117*4882a593Smuzhiyun setversion_out:
118*4882a593Smuzhiyun mnt_drop_write_file(filp);
119*4882a593Smuzhiyun break;
120*4882a593Smuzhiyun default:
121*4882a593Smuzhiyun err = -ENOTTY;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun reiserfs_write_unlock(inode->i_sb);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return err;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
reiserfs_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)130*4882a593Smuzhiyun long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
131*4882a593Smuzhiyun unsigned long arg)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun /*
134*4882a593Smuzhiyun * These are just misnamed, they actually
135*4882a593Smuzhiyun * get/put from/to user an int
136*4882a593Smuzhiyun */
137*4882a593Smuzhiyun switch (cmd) {
138*4882a593Smuzhiyun case REISERFS_IOC32_UNPACK:
139*4882a593Smuzhiyun cmd = REISERFS_IOC_UNPACK;
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun case REISERFS_IOC32_GETFLAGS:
142*4882a593Smuzhiyun cmd = REISERFS_IOC_GETFLAGS;
143*4882a593Smuzhiyun break;
144*4882a593Smuzhiyun case REISERFS_IOC32_SETFLAGS:
145*4882a593Smuzhiyun cmd = REISERFS_IOC_SETFLAGS;
146*4882a593Smuzhiyun break;
147*4882a593Smuzhiyun case REISERFS_IOC32_GETVERSION:
148*4882a593Smuzhiyun cmd = REISERFS_IOC_GETVERSION;
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun case REISERFS_IOC32_SETVERSION:
151*4882a593Smuzhiyun cmd = REISERFS_IOC_SETVERSION;
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun default:
154*4882a593Smuzhiyun return -ENOIOCTLCMD;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun #endif
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun int reiserfs_commit_write(struct file *f, struct page *page,
162*4882a593Smuzhiyun unsigned from, unsigned to);
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun * reiserfs_unpack
165*4882a593Smuzhiyun * Function try to convert tail from direct item into indirect.
166*4882a593Smuzhiyun * It set up nopack attribute in the REISERFS_I(inode)->nopack
167*4882a593Smuzhiyun */
reiserfs_unpack(struct inode * inode,struct file * filp)168*4882a593Smuzhiyun int reiserfs_unpack(struct inode *inode, struct file *filp)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun int retval = 0;
171*4882a593Smuzhiyun int index;
172*4882a593Smuzhiyun struct page *page;
173*4882a593Smuzhiyun struct address_space *mapping;
174*4882a593Smuzhiyun unsigned long write_from;
175*4882a593Smuzhiyun unsigned long blocksize = inode->i_sb->s_blocksize;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (inode->i_size == 0) {
178*4882a593Smuzhiyun REISERFS_I(inode)->i_flags |= i_nopack_mask;
179*4882a593Smuzhiyun return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun /* ioctl already done */
182*4882a593Smuzhiyun if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
183*4882a593Smuzhiyun return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* we need to make sure nobody is changing the file size beneath us */
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun int depth = reiserfs_write_unlock_nested(inode->i_sb);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun inode_lock(inode);
191*4882a593Smuzhiyun reiserfs_write_lock_nested(inode->i_sb, depth);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun reiserfs_write_lock(inode->i_sb);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun write_from = inode->i_size & (blocksize - 1);
197*4882a593Smuzhiyun /* if we are on a block boundary, we are already unpacked. */
198*4882a593Smuzhiyun if (write_from == 0) {
199*4882a593Smuzhiyun REISERFS_I(inode)->i_flags |= i_nopack_mask;
200*4882a593Smuzhiyun goto out;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * we unpack by finding the page with the tail, and calling
205*4882a593Smuzhiyun * __reiserfs_write_begin on that page. This will force a
206*4882a593Smuzhiyun * reiserfs_get_block to unpack the tail for us.
207*4882a593Smuzhiyun */
208*4882a593Smuzhiyun index = inode->i_size >> PAGE_SHIFT;
209*4882a593Smuzhiyun mapping = inode->i_mapping;
210*4882a593Smuzhiyun page = grab_cache_page(mapping, index);
211*4882a593Smuzhiyun retval = -ENOMEM;
212*4882a593Smuzhiyun if (!page) {
213*4882a593Smuzhiyun goto out;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun retval = __reiserfs_write_begin(page, write_from, 0);
216*4882a593Smuzhiyun if (retval)
217*4882a593Smuzhiyun goto out_unlock;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* conversion can change page contents, must flush */
220*4882a593Smuzhiyun flush_dcache_page(page);
221*4882a593Smuzhiyun retval = reiserfs_commit_write(NULL, page, write_from, write_from);
222*4882a593Smuzhiyun REISERFS_I(inode)->i_flags |= i_nopack_mask;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun out_unlock:
225*4882a593Smuzhiyun unlock_page(page);
226*4882a593Smuzhiyun put_page(page);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun out:
229*4882a593Smuzhiyun inode_unlock(inode);
230*4882a593Smuzhiyun reiserfs_write_unlock(inode->i_sb);
231*4882a593Smuzhiyun return retval;
232*4882a593Smuzhiyun }
233