1 #include <linux/in.h> 2 3 #include "ioctl.h" 4 #include "super.h" 5 #include "ceph_debug.h" 6 7 8 /* 9 * ioctls 10 */ 11 12 /* 13 * get and set the file layout 14 */ 15 static long ceph_ioctl_get_layout(struct file *file, void __user *arg) 16 { 17 struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode); 18 struct ceph_ioctl_layout l; 19 int err; 20 21 err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT); 22 if (!err) { 23 l.stripe_unit = ceph_file_layout_su(ci->i_layout); 24 l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout); 25 l.object_size = ceph_file_layout_object_size(ci->i_layout); 26 l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool); 27 l.preferred_osd = 28 (s32)le32_to_cpu(ci->i_layout.fl_pg_preferred); 29 if (copy_to_user(arg, &l, sizeof(l))) 30 return -EFAULT; 31 } 32 33 return err; 34 } 35 36 static long ceph_ioctl_set_layout(struct file *file, void __user *arg) 37 { 38 struct inode *inode = file->f_dentry->d_inode; 39 struct inode *parent_inode = file->f_dentry->d_parent->d_inode; 40 struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc; 41 struct ceph_mds_request *req; 42 struct ceph_ioctl_layout l; 43 int err, i; 44 45 /* copy and validate */ 46 if (copy_from_user(&l, arg, sizeof(l))) 47 return -EFAULT; 48 49 if ((l.object_size & ~PAGE_MASK) || 50 (l.stripe_unit & ~PAGE_MASK) || 51 !l.stripe_unit || 52 (l.object_size && 53 (unsigned)l.object_size % (unsigned)l.stripe_unit)) 54 return -EINVAL; 55 56 /* make sure it's a valid data pool */ 57 if (l.data_pool > 0) { 58 mutex_lock(&mdsc->mutex); 59 err = -EINVAL; 60 for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++) 61 if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) { 62 err = 0; 63 break; 64 } 65 mutex_unlock(&mdsc->mutex); 66 if (err) 67 return err; 68 } 69 70 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT, 71 USE_AUTH_MDS); 72 if (IS_ERR(req)) 73 return PTR_ERR(req); 74 req->r_inode = igrab(inode); 75 req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL; 76 77 req->r_args.setlayout.layout.fl_stripe_unit = 78 cpu_to_le32(l.stripe_unit); 79 req->r_args.setlayout.layout.fl_stripe_count = 80 cpu_to_le32(l.stripe_count); 81 req->r_args.setlayout.layout.fl_object_size = 82 cpu_to_le32(l.object_size); 83 req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool); 84 req->r_args.setlayout.layout.fl_pg_preferred = 85 cpu_to_le32(l.preferred_osd); 86 87 err = ceph_mdsc_do_request(mdsc, parent_inode, req); 88 ceph_mdsc_put_request(req); 89 return err; 90 } 91 92 /* 93 * Return object name, size/offset information, and location (OSD 94 * number, network address) for a given file offset. 95 */ 96 static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) 97 { 98 struct ceph_ioctl_dataloc dl; 99 struct inode *inode = file->f_dentry->d_inode; 100 struct ceph_inode_info *ci = ceph_inode(inode); 101 struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc; 102 u64 len = 1, olen; 103 u64 tmp; 104 struct ceph_object_layout ol; 105 struct ceph_pg pgid; 106 107 /* copy and validate */ 108 if (copy_from_user(&dl, arg, sizeof(dl))) 109 return -EFAULT; 110 111 down_read(&osdc->map_sem); 112 ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len, 113 &dl.object_no, &dl.object_offset, &olen); 114 dl.file_offset -= dl.object_offset; 115 dl.object_size = ceph_file_layout_object_size(ci->i_layout); 116 dl.block_size = ceph_file_layout_su(ci->i_layout); 117 118 /* block_offset = object_offset % block_size */ 119 tmp = dl.object_offset; 120 dl.block_offset = do_div(tmp, dl.block_size); 121 122 snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx", 123 ceph_ino(inode), dl.object_no); 124 ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout, 125 osdc->osdmap); 126 127 pgid = ol.ol_pgid; 128 dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid); 129 if (dl.osd >= 0) { 130 struct ceph_entity_addr *a = 131 ceph_osd_addr(osdc->osdmap, dl.osd); 132 if (a) 133 memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr)); 134 } else { 135 memset(&dl.osd_addr, 0, sizeof(dl.osd_addr)); 136 } 137 up_read(&osdc->map_sem); 138 139 /* send result back to user */ 140 if (copy_to_user(arg, &dl, sizeof(dl))) 141 return -EFAULT; 142 143 return 0; 144 } 145 146 static long ceph_ioctl_lazyio(struct file *file) 147 { 148 struct ceph_file_info *fi = file->private_data; 149 struct inode *inode = file->f_dentry->d_inode; 150 struct ceph_inode_info *ci = ceph_inode(inode); 151 152 if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) { 153 spin_lock(&inode->i_lock); 154 ci->i_nr_by_mode[fi->fmode]--; 155 fi->fmode |= CEPH_FILE_MODE_LAZY; 156 ci->i_nr_by_mode[fi->fmode]++; 157 spin_unlock(&inode->i_lock); 158 dout("ioctl_layzio: file %p marked lazy\n", file); 159 160 ceph_check_caps(ci, 0, NULL); 161 } else { 162 dout("ioctl_layzio: file %p already lazy\n", file); 163 } 164 return 0; 165 } 166 167 long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 168 { 169 dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); 170 switch (cmd) { 171 case CEPH_IOC_GET_LAYOUT: 172 return ceph_ioctl_get_layout(file, (void __user *)arg); 173 174 case CEPH_IOC_SET_LAYOUT: 175 return ceph_ioctl_set_layout(file, (void __user *)arg); 176 177 case CEPH_IOC_GET_DATALOC: 178 return ceph_ioctl_get_dataloc(file, (void __user *)arg); 179 180 case CEPH_IOC_LAZYIO: 181 return ceph_ioctl_lazyio(file); 182 } 183 return -ENOTTY; 184 } 185