Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * ioctls
0012  */
0013 
0014 /*
0015  * get and set the file layout
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     /* validate striping parameters */
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     /* make sure it's a valid data pool */
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     /* validate changed params against current layout */
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     /* this is obsolete, and always -1 */
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  * Set a layout policy on a directory inode. All items in the tree
0132  * rooted at this inode will inherit this layout on creation,
0133  * (It doesn't apply retroactively )
0134  * unless a subdirectory has its own layout policy.
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     /* copy and validate */
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  * Return object name, size/offset information, and location (OSD
0177  * number, network address) for a given file offset.
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     /* copy and validate */
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     /* block_offset = object_offset % block_size */
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     /* send result back to user */
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 }