Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / fs / ceph / ioctl.c
1 #include <linux/in.h>
2
3 #include "super.h"
4 #include "mds_client.h"
5 #include <linux/ceph/ceph_debug.h>
6
7 #include "ioctl.h"
8
9
10 /*
11  * ioctls
12  */
13
14 /*
15  * get and set the file layout
16  */
17 static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
18 {
19         struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
20         struct ceph_ioctl_layout l;
21         int err;
22
23         err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
24         if (!err) {
25                 l.stripe_unit = ceph_file_layout_su(ci->i_layout);
26                 l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
27                 l.object_size = ceph_file_layout_object_size(ci->i_layout);
28                 l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
29                 l.preferred_osd = (s32)-1;
30                 if (copy_to_user(arg, &l, sizeof(l)))
31                         return -EFAULT;
32         }
33
34         return err;
35 }
36
37 static long __validate_layout(struct ceph_mds_client *mdsc,
38                               struct ceph_ioctl_layout *l)
39 {
40         int i, err;
41
42         /* validate striping parameters */
43         if ((l->object_size & ~PAGE_MASK) ||
44             (l->stripe_unit & ~PAGE_MASK) ||
45             ((unsigned)l->object_size % (unsigned)l->stripe_unit))
46                 return -EINVAL;
47
48         /* make sure it's a valid data pool */
49         mutex_lock(&mdsc->mutex);
50         err = -EINVAL;
51         for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
52                 if (mdsc->mdsmap->m_data_pg_pools[i] == l->data_pool) {
53                         err = 0;
54                         break;
55                 }
56         mutex_unlock(&mdsc->mutex);
57         if (err)
58                 return err;
59
60         return 0;
61 }
62
63 static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
64 {
65         struct inode *inode = file->f_dentry->d_inode;
66         struct inode *parent_inode;
67         struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
68         struct ceph_mds_request *req;
69         struct ceph_ioctl_layout l;
70         struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
71         struct ceph_ioctl_layout nl;
72         int err;
73
74         if (copy_from_user(&l, arg, sizeof(l)))
75                 return -EFAULT;
76
77         /* validate changed params against current layout */
78         err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
79         if (err)
80                 return err;
81
82         memset(&nl, 0, sizeof(nl));
83         if (l.stripe_count)
84                 nl.stripe_count = l.stripe_count;
85         else
86                 nl.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
87         if (l.stripe_unit)
88                 nl.stripe_unit = l.stripe_unit;
89         else
90                 nl.stripe_unit = ceph_file_layout_su(ci->i_layout);
91         if (l.object_size)
92                 nl.object_size = l.object_size;
93         else
94                 nl.object_size = ceph_file_layout_object_size(ci->i_layout);
95         if (l.data_pool)
96                 nl.data_pool = l.data_pool;
97         else
98                 nl.data_pool = ceph_file_layout_pg_pool(ci->i_layout);
99
100         /* this is obsolete, and always -1 */
101         nl.preferred_osd = le64_to_cpu(-1);
102
103         err = __validate_layout(mdsc, &nl);
104         if (err)
105                 return err;
106
107         req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
108                                        USE_AUTH_MDS);
109         if (IS_ERR(req))
110                 return PTR_ERR(req);
111         req->r_inode = inode;
112         ihold(inode);
113         req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
114
115         req->r_args.setlayout.layout.fl_stripe_unit =
116                 cpu_to_le32(l.stripe_unit);
117         req->r_args.setlayout.layout.fl_stripe_count =
118                 cpu_to_le32(l.stripe_count);
119         req->r_args.setlayout.layout.fl_object_size =
120                 cpu_to_le32(l.object_size);
121         req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
122
123         parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
124         err = ceph_mdsc_do_request(mdsc, parent_inode, req);
125         iput(parent_inode);
126         ceph_mdsc_put_request(req);
127         return err;
128 }
129
130 /*
131  * Set a layout policy on a directory inode. All items in the tree
132  * rooted at this inode will inherit this layout on creation,
133  * (It doesn't apply retroactively )
134  * unless a subdirectory has its own layout policy.
135  */
136 static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
137 {
138         struct inode *inode = file->f_dentry->d_inode;
139         struct ceph_mds_request *req;
140         struct ceph_ioctl_layout l;
141         int err;
142         struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
143
144         /* copy and validate */
145         if (copy_from_user(&l, arg, sizeof(l)))
146                 return -EFAULT;
147
148         err = __validate_layout(mdsc, &l);
149         if (err)
150                 return err;
151
152         req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
153                                        USE_AUTH_MDS);
154
155         if (IS_ERR(req))
156                 return PTR_ERR(req);
157         req->r_inode = inode;
158         ihold(inode);
159
160         req->r_args.setlayout.layout.fl_stripe_unit =
161                         cpu_to_le32(l.stripe_unit);
162         req->r_args.setlayout.layout.fl_stripe_count =
163                         cpu_to_le32(l.stripe_count);
164         req->r_args.setlayout.layout.fl_object_size =
165                         cpu_to_le32(l.object_size);
166         req->r_args.setlayout.layout.fl_pg_pool =
167                         cpu_to_le32(l.data_pool);
168
169         err = ceph_mdsc_do_request(mdsc, inode, req);
170         ceph_mdsc_put_request(req);
171         return err;
172 }
173
174 /*
175  * Return object name, size/offset information, and location (OSD
176  * number, network address) for a given file offset.
177  */
178 static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
179 {
180         struct ceph_ioctl_dataloc dl;
181         struct inode *inode = file->f_dentry->d_inode;
182         struct ceph_inode_info *ci = ceph_inode(inode);
183         struct ceph_osd_client *osdc =
184                 &ceph_sb_to_client(inode->i_sb)->client->osdc;
185         u64 len = 1, olen;
186         u64 tmp;
187         struct ceph_object_layout ol;
188         struct ceph_pg pgid;
189
190         /* copy and validate */
191         if (copy_from_user(&dl, arg, sizeof(dl)))
192                 return -EFAULT;
193
194         down_read(&osdc->map_sem);
195         ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len,
196                                       &dl.object_no, &dl.object_offset, &olen);
197         dl.file_offset -= dl.object_offset;
198         dl.object_size = ceph_file_layout_object_size(ci->i_layout);
199         dl.block_size = ceph_file_layout_su(ci->i_layout);
200
201         /* block_offset = object_offset % block_size */
202         tmp = dl.object_offset;
203         dl.block_offset = do_div(tmp, dl.block_size);
204
205         snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
206                  ceph_ino(inode), dl.object_no);
207         ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout,
208                                 osdc->osdmap);
209
210         pgid = ol.ol_pgid;
211         dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
212         if (dl.osd >= 0) {
213                 struct ceph_entity_addr *a =
214                         ceph_osd_addr(osdc->osdmap, dl.osd);
215                 if (a)
216                         memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
217         } else {
218                 memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
219         }
220         up_read(&osdc->map_sem);
221
222         /* send result back to user */
223         if (copy_to_user(arg, &dl, sizeof(dl)))
224                 return -EFAULT;
225
226         return 0;
227 }
228
229 static long ceph_ioctl_lazyio(struct file *file)
230 {
231         struct ceph_file_info *fi = file->private_data;
232         struct inode *inode = file->f_dentry->d_inode;
233         struct ceph_inode_info *ci = ceph_inode(inode);
234
235         if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
236                 spin_lock(&ci->i_ceph_lock);
237                 ci->i_nr_by_mode[fi->fmode]--;
238                 fi->fmode |= CEPH_FILE_MODE_LAZY;
239                 ci->i_nr_by_mode[fi->fmode]++;
240                 spin_unlock(&ci->i_ceph_lock);
241                 dout("ioctl_layzio: file %p marked lazy\n", file);
242
243                 ceph_check_caps(ci, 0, NULL);
244         } else {
245                 dout("ioctl_layzio: file %p already lazy\n", file);
246         }
247         return 0;
248 }
249
250 static long ceph_ioctl_syncio(struct file *file)
251 {
252         struct ceph_file_info *fi = file->private_data;
253
254         fi->flags |= CEPH_F_SYNC;
255         return 0;
256 }
257
258 long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
259 {
260         dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
261         switch (cmd) {
262         case CEPH_IOC_GET_LAYOUT:
263                 return ceph_ioctl_get_layout(file, (void __user *)arg);
264
265         case CEPH_IOC_SET_LAYOUT:
266                 return ceph_ioctl_set_layout(file, (void __user *)arg);
267
268         case CEPH_IOC_SET_LAYOUT_POLICY:
269                 return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
270
271         case CEPH_IOC_GET_DATALOC:
272                 return ceph_ioctl_get_dataloc(file, (void __user *)arg);
273
274         case CEPH_IOC_LAZYIO:
275                 return ceph_ioctl_lazyio(file);
276
277         case CEPH_IOC_SYNCIO:
278                 return ceph_ioctl_syncio(file);
279         }
280
281         return -ENOTTY;
282 }