linux/fs/ceph/ioctl.c
<<
>>
Prefs
   1#include <linux/in.h>
   2
   3#include "super.h"
   4#include "mds_client.h"
   5#include <linux/ceph/ceph_debug.h>
   6
   7#include "ioctl.h"
   8
   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);
  24        if (!err) {
  25                l.stripe_unit = ceph_file_layout_su(ci->i_layout);
  26                l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
  27                l.object_size = ceph_file_layout_object_size(ci->i_layout);
  28                l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
  29                l.preferred_osd = (s32)-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            (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 inode *parent_inode;
  68        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
  69        struct ceph_mds_request *req;
  70        struct ceph_ioctl_layout l;
  71        struct ceph_inode_info *ci = ceph_inode(file_inode(file));
  72        struct ceph_ioctl_layout nl;
  73        int err;
  74
  75        if (copy_from_user(&l, arg, sizeof(l)))
  76                return -EFAULT;
  77
  78        /* validate changed params against current layout */
  79        err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT);
  80        if (err)
  81                return err;
  82
  83        memset(&nl, 0, sizeof(nl));
  84        if (l.stripe_count)
  85                nl.stripe_count = l.stripe_count;
  86        else
  87                nl.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
  88        if (l.stripe_unit)
  89                nl.stripe_unit = l.stripe_unit;
  90        else
  91                nl.stripe_unit = ceph_file_layout_su(ci->i_layout);
  92        if (l.object_size)
  93                nl.object_size = l.object_size;
  94        else
  95                nl.object_size = ceph_file_layout_object_size(ci->i_layout);
  96        if (l.data_pool)
  97                nl.data_pool = l.data_pool;
  98        else
  99                nl.data_pool = ceph_file_layout_pg_pool(ci->i_layout);
 100
 101        /* this is obsolete, and always -1 */
 102        nl.preferred_osd = le64_to_cpu(-1);
 103
 104        err = __validate_layout(mdsc, &nl);
 105        if (err)
 106                return err;
 107
 108        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
 109                                       USE_AUTH_MDS);
 110        if (IS_ERR(req))
 111                return PTR_ERR(req);
 112        req->r_inode = inode;
 113        ihold(inode);
 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        parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
 125        err = ceph_mdsc_do_request(mdsc, parent_inode, req);
 126        iput(parent_inode);
 127        ceph_mdsc_put_request(req);
 128        return err;
 129}
 130
 131/*
 132 * Set a layout policy on a directory inode. All items in the tree
 133 * rooted at this inode will inherit this layout on creation,
 134 * (It doesn't apply retroactively )
 135 * unless a subdirectory has its own layout policy.
 136 */
 137static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
 138{
 139        struct inode *inode = file_inode(file);
 140        struct ceph_mds_request *req;
 141        struct ceph_ioctl_layout l;
 142        int err;
 143        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
 144
 145        /* copy and validate */
 146        if (copy_from_user(&l, arg, sizeof(l)))
 147                return -EFAULT;
 148
 149        err = __validate_layout(mdsc, &l);
 150        if (err)
 151                return err;
 152
 153        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
 154                                       USE_AUTH_MDS);
 155
 156        if (IS_ERR(req))
 157                return PTR_ERR(req);
 158        req->r_inode = inode;
 159        ihold(inode);
 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        u64 len = 1, olen;
 187        u64 tmp;
 188        struct ceph_pg pgid;
 189        int r;
 190
 191        /* copy and validate */
 192        if (copy_from_user(&dl, arg, sizeof(dl)))
 193                return -EFAULT;
 194
 195        down_read(&osdc->map_sem);
 196        r = ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, len,
 197                                          &dl.object_no, &dl.object_offset,
 198                                          &olen);
 199        if (r < 0)
 200                return -EIO;
 201        dl.file_offset -= dl.object_offset;
 202        dl.object_size = ceph_file_layout_object_size(ci->i_layout);
 203        dl.block_size = ceph_file_layout_su(ci->i_layout);
 204
 205        /* block_offset = object_offset % block_size */
 206        tmp = dl.object_offset;
 207        dl.block_offset = do_div(tmp, dl.block_size);
 208
 209        snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
 210                 ceph_ino(inode), dl.object_no);
 211
 212        ceph_calc_ceph_pg(&pgid, dl.object_name, osdc->osdmap,
 213                ceph_file_layout_pg_pool(ci->i_layout));
 214
 215        dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
 216        if (dl.osd >= 0) {
 217                struct ceph_entity_addr *a =
 218                        ceph_osd_addr(osdc->osdmap, dl.osd);
 219                if (a)
 220                        memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
 221        } else {
 222                memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
 223        }
 224        up_read(&osdc->map_sem);
 225
 226        /* send result back to user */
 227        if (copy_to_user(arg, &dl, sizeof(dl)))
 228                return -EFAULT;
 229
 230        return 0;
 231}
 232
 233static long ceph_ioctl_lazyio(struct file *file)
 234{
 235        struct ceph_file_info *fi = file->private_data;
 236        struct inode *inode = file_inode(file);
 237        struct ceph_inode_info *ci = ceph_inode(inode);
 238
 239        if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
 240                spin_lock(&ci->i_ceph_lock);
 241                ci->i_nr_by_mode[fi->fmode]--;
 242                fi->fmode |= CEPH_FILE_MODE_LAZY;
 243                ci->i_nr_by_mode[fi->fmode]++;
 244                spin_unlock(&ci->i_ceph_lock);
 245                dout("ioctl_layzio: file %p marked lazy\n", file);
 246
 247                ceph_check_caps(ci, 0, NULL);
 248        } else {
 249                dout("ioctl_layzio: file %p already lazy\n", file);
 250        }
 251        return 0;
 252}
 253
 254static long ceph_ioctl_syncio(struct file *file)
 255{
 256        struct ceph_file_info *fi = file->private_data;
 257
 258        fi->flags |= CEPH_F_SYNC;
 259        return 0;
 260}
 261
 262long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 263{
 264        dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
 265        switch (cmd) {
 266        case CEPH_IOC_GET_LAYOUT:
 267                return ceph_ioctl_get_layout(file, (void __user *)arg);
 268
 269        case CEPH_IOC_SET_LAYOUT:
 270                return ceph_ioctl_set_layout(file, (void __user *)arg);
 271
 272        case CEPH_IOC_SET_LAYOUT_POLICY:
 273                return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
 274
 275        case CEPH_IOC_GET_DATALOC:
 276                return ceph_ioctl_get_dataloc(file, (void __user *)arg);
 277
 278        case CEPH_IOC_LAZYIO:
 279                return ceph_ioctl_lazyio(file);
 280
 281        case CEPH_IOC_SYNCIO:
 282                return ceph_ioctl_syncio(file);
 283        }
 284
 285        return -ENOTTY;
 286}
 287