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