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