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