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