xref: /OK3568_Linux_fs/kernel/fs/reiserfs/ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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