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