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