0001
0002 #include <linux/ceph/ceph_debug.h>
0003 #include <linux/in.h>
0004
0005 #include "super.h"
0006 #include "mds_client.h"
0007 #include "ioctl.h"
0008 #include <linux/ceph/striper.h>
0009
0010
0011
0012
0013
0014
0015
0016
0017 static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
0018 {
0019 struct ceph_inode_info *ci = ceph_inode(file_inode(file));
0020 struct ceph_ioctl_layout l;
0021 int err;
0022
0023 err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
0024 if (!err) {
0025 l.stripe_unit = ci->i_layout.stripe_unit;
0026 l.stripe_count = ci->i_layout.stripe_count;
0027 l.object_size = ci->i_layout.object_size;
0028 l.data_pool = ci->i_layout.pool_id;
0029 l.preferred_osd = -1;
0030 if (copy_to_user(arg, &l, sizeof(l)))
0031 return -EFAULT;
0032 }
0033
0034 return err;
0035 }
0036
0037 static long __validate_layout(struct ceph_mds_client *mdsc,
0038 struct ceph_ioctl_layout *l)
0039 {
0040 int i, err;
0041
0042
0043 if ((l->object_size & ~PAGE_MASK) ||
0044 (l->stripe_unit & ~PAGE_MASK) ||
0045 ((unsigned)l->stripe_unit != 0 &&
0046 ((unsigned)l->object_size % (unsigned)l->stripe_unit)))
0047 return -EINVAL;
0048
0049
0050 mutex_lock(&mdsc->mutex);
0051 err = -EINVAL;
0052 for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
0053 if (mdsc->mdsmap->m_data_pg_pools[i] == l->data_pool) {
0054 err = 0;
0055 break;
0056 }
0057 mutex_unlock(&mdsc->mutex);
0058 if (err)
0059 return err;
0060
0061 return 0;
0062 }
0063
0064 static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
0065 {
0066 struct inode *inode = file_inode(file);
0067 struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
0068 struct ceph_mds_request *req;
0069 struct ceph_ioctl_layout l;
0070 struct ceph_inode_info *ci = ceph_inode(file_inode(file));
0071 struct ceph_ioctl_layout nl;
0072 int err;
0073
0074 if (copy_from_user(&l, arg, sizeof(l)))
0075 return -EFAULT;
0076
0077
0078 err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
0079 if (err)
0080 return err;
0081
0082 memset(&nl, 0, sizeof(nl));
0083 if (l.stripe_count)
0084 nl.stripe_count = l.stripe_count;
0085 else
0086 nl.stripe_count = ci->i_layout.stripe_count;
0087 if (l.stripe_unit)
0088 nl.stripe_unit = l.stripe_unit;
0089 else
0090 nl.stripe_unit = ci->i_layout.stripe_unit;
0091 if (l.object_size)
0092 nl.object_size = l.object_size;
0093 else
0094 nl.object_size = ci->i_layout.object_size;
0095 if (l.data_pool)
0096 nl.data_pool = l.data_pool;
0097 else
0098 nl.data_pool = ci->i_layout.pool_id;
0099
0100
0101 nl.preferred_osd = -1;
0102
0103 err = __validate_layout(mdsc, &nl);
0104 if (err)
0105 return err;
0106
0107 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
0108 USE_AUTH_MDS);
0109 if (IS_ERR(req))
0110 return PTR_ERR(req);
0111 req->r_inode = inode;
0112 ihold(inode);
0113 req->r_num_caps = 1;
0114
0115 req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
0116
0117 req->r_args.setlayout.layout.fl_stripe_unit =
0118 cpu_to_le32(l.stripe_unit);
0119 req->r_args.setlayout.layout.fl_stripe_count =
0120 cpu_to_le32(l.stripe_count);
0121 req->r_args.setlayout.layout.fl_object_size =
0122 cpu_to_le32(l.object_size);
0123 req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
0124
0125 err = ceph_mdsc_do_request(mdsc, NULL, req);
0126 ceph_mdsc_put_request(req);
0127 return err;
0128 }
0129
0130
0131
0132
0133
0134
0135
0136 static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
0137 {
0138 struct inode *inode = file_inode(file);
0139 struct ceph_mds_request *req;
0140 struct ceph_ioctl_layout l;
0141 int err;
0142 struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
0143
0144
0145 if (copy_from_user(&l, arg, sizeof(l)))
0146 return -EFAULT;
0147
0148 err = __validate_layout(mdsc, &l);
0149 if (err)
0150 return err;
0151
0152 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
0153 USE_AUTH_MDS);
0154
0155 if (IS_ERR(req))
0156 return PTR_ERR(req);
0157 req->r_inode = inode;
0158 ihold(inode);
0159 req->r_num_caps = 1;
0160
0161 req->r_args.setlayout.layout.fl_stripe_unit =
0162 cpu_to_le32(l.stripe_unit);
0163 req->r_args.setlayout.layout.fl_stripe_count =
0164 cpu_to_le32(l.stripe_count);
0165 req->r_args.setlayout.layout.fl_object_size =
0166 cpu_to_le32(l.object_size);
0167 req->r_args.setlayout.layout.fl_pg_pool =
0168 cpu_to_le32(l.data_pool);
0169
0170 err = ceph_mdsc_do_request(mdsc, inode, req);
0171 ceph_mdsc_put_request(req);
0172 return err;
0173 }
0174
0175
0176
0177
0178
0179 static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
0180 {
0181 struct ceph_ioctl_dataloc dl;
0182 struct inode *inode = file_inode(file);
0183 struct ceph_inode_info *ci = ceph_inode(inode);
0184 struct ceph_osd_client *osdc =
0185 &ceph_sb_to_client(inode->i_sb)->client->osdc;
0186 struct ceph_object_locator oloc;
0187 CEPH_DEFINE_OID_ONSTACK(oid);
0188 u32 xlen;
0189 u64 tmp;
0190 struct ceph_pg pgid;
0191 int r;
0192
0193
0194 if (copy_from_user(&dl, arg, sizeof(dl)))
0195 return -EFAULT;
0196
0197 down_read(&osdc->lock);
0198 ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, 1,
0199 &dl.object_no, &dl.object_offset, &xlen);
0200 dl.file_offset -= dl.object_offset;
0201 dl.object_size = ci->i_layout.object_size;
0202 dl.block_size = ci->i_layout.stripe_unit;
0203
0204
0205 tmp = dl.object_offset;
0206 dl.block_offset = do_div(tmp, dl.block_size);
0207
0208 snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
0209 ceph_ino(inode), dl.object_no);
0210
0211 oloc.pool = ci->i_layout.pool_id;
0212 oloc.pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
0213 ceph_oid_printf(&oid, "%s", dl.object_name);
0214
0215 r = ceph_object_locator_to_pg(osdc->osdmap, &oid, &oloc, &pgid);
0216
0217 ceph_oloc_destroy(&oloc);
0218 if (r < 0) {
0219 up_read(&osdc->lock);
0220 return r;
0221 }
0222
0223 dl.osd = ceph_pg_to_acting_primary(osdc->osdmap, &pgid);
0224 if (dl.osd >= 0) {
0225 struct ceph_entity_addr *a =
0226 ceph_osd_addr(osdc->osdmap, dl.osd);
0227 if (a)
0228 memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
0229 } else {
0230 memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
0231 }
0232 up_read(&osdc->lock);
0233
0234
0235 if (copy_to_user(arg, &dl, sizeof(dl)))
0236 return -EFAULT;
0237
0238 return 0;
0239 }
0240
0241 static long ceph_ioctl_lazyio(struct file *file)
0242 {
0243 struct ceph_file_info *fi = file->private_data;
0244 struct inode *inode = file_inode(file);
0245 struct ceph_inode_info *ci = ceph_inode(inode);
0246 struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
0247
0248 if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
0249 spin_lock(&ci->i_ceph_lock);
0250 fi->fmode |= CEPH_FILE_MODE_LAZY;
0251 ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
0252 __ceph_touch_fmode(ci, mdsc, fi->fmode);
0253 spin_unlock(&ci->i_ceph_lock);
0254 dout("ioctl_layzio: file %p marked lazy\n", file);
0255
0256 ceph_check_caps(ci, 0, NULL);
0257 } else {
0258 dout("ioctl_layzio: file %p already lazy\n", file);
0259 }
0260 return 0;
0261 }
0262
0263 static long ceph_ioctl_syncio(struct file *file)
0264 {
0265 struct ceph_file_info *fi = file->private_data;
0266
0267 fi->flags |= CEPH_F_SYNC;
0268 return 0;
0269 }
0270
0271 long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0272 {
0273 dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
0274 switch (cmd) {
0275 case CEPH_IOC_GET_LAYOUT:
0276 return ceph_ioctl_get_layout(file, (void __user *)arg);
0277
0278 case CEPH_IOC_SET_LAYOUT:
0279 return ceph_ioctl_set_layout(file, (void __user *)arg);
0280
0281 case CEPH_IOC_SET_LAYOUT_POLICY:
0282 return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
0283
0284 case CEPH_IOC_GET_DATALOC:
0285 return ceph_ioctl_get_dataloc(file, (void __user *)arg);
0286
0287 case CEPH_IOC_LAZYIO:
0288 return ceph_ioctl_lazyio(file);
0289
0290 case CEPH_IOC_SYNCIO:
0291 return ceph_ioctl_syncio(file);
0292 }
0293
0294 return -ENOTTY;
0295 }