linux/fs/ocfs2/ioctl.c
<<
>>
Prefs
   1/*
   2 * linux/fs/ocfs2/ioctl.c
   3 *
   4 * Copyright (C) 2006 Herbert Poetzl
   5 * adapted from Remy Card's ext2/ioctl.c
   6 */
   7
   8#include <linux/fs.h>
   9#include <linux/mount.h>
  10#include <linux/compat.h>
  11
  12#include <cluster/masklog.h>
  13
  14#include "ocfs2.h"
  15#include "alloc.h"
  16#include "dlmglue.h"
  17#include "file.h"
  18#include "inode.h"
  19#include "journal.h"
  20
  21#include "ocfs2_fs.h"
  22#include "ioctl.h"
  23#include "resize.h"
  24#include "refcounttree.h"
  25
  26#include <linux/ext2_fs.h>
  27
  28#define o2info_from_user(a, b)  \
  29                copy_from_user(&(a), (b), sizeof(a))
  30#define o2info_to_user(a, b)    \
  31                copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
  32
  33/*
  34 * This call is void because we are already reporting an error that may
  35 * be -EFAULT.  The error will be returned from the ioctl(2) call.  It's
  36 * just a best-effort to tell userspace that this request caused the error.
  37 */
  38static inline void __o2info_set_request_error(struct ocfs2_info_request *kreq,
  39                                        struct ocfs2_info_request __user *req)
  40{
  41        kreq->ir_flags |= OCFS2_INFO_FL_ERROR;
  42        (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags));
  43}
  44
  45#define o2info_set_request_error(a, b) \
  46                __o2info_set_request_error((struct ocfs2_info_request *)&(a), b)
  47
  48static inline void __o2info_set_request_filled(struct ocfs2_info_request *req)
  49{
  50        req->ir_flags |= OCFS2_INFO_FL_FILLED;
  51}
  52
  53#define o2info_set_request_filled(a) \
  54                __o2info_set_request_filled((struct ocfs2_info_request *)&(a))
  55
  56static inline void __o2info_clear_request_filled(struct ocfs2_info_request *req)
  57{
  58        req->ir_flags &= ~OCFS2_INFO_FL_FILLED;
  59}
  60
  61#define o2info_clear_request_filled(a) \
  62                __o2info_clear_request_filled((struct ocfs2_info_request *)&(a))
  63
  64static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
  65{
  66        int status;
  67
  68        status = ocfs2_inode_lock(inode, NULL, 0);
  69        if (status < 0) {
  70                mlog_errno(status);
  71                return status;
  72        }
  73        ocfs2_get_inode_flags(OCFS2_I(inode));
  74        *flags = OCFS2_I(inode)->ip_attr;
  75        ocfs2_inode_unlock(inode, 0);
  76
  77        return status;
  78}
  79
  80static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
  81                                unsigned mask)
  82{
  83        struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode);
  84        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  85        handle_t *handle = NULL;
  86        struct buffer_head *bh = NULL;
  87        unsigned oldflags;
  88        int status;
  89
  90        mutex_lock(&inode->i_mutex);
  91
  92        status = ocfs2_inode_lock(inode, &bh, 1);
  93        if (status < 0) {
  94                mlog_errno(status);
  95                goto bail;
  96        }
  97
  98        status = -EACCES;
  99        if (!inode_owner_or_capable(inode))
 100                goto bail_unlock;
 101
 102        if (!S_ISDIR(inode->i_mode))
 103                flags &= ~OCFS2_DIRSYNC_FL;
 104
 105        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
 106        if (IS_ERR(handle)) {
 107                status = PTR_ERR(handle);
 108                mlog_errno(status);
 109                goto bail_unlock;
 110        }
 111
 112        oldflags = ocfs2_inode->ip_attr;
 113        flags = flags & mask;
 114        flags |= oldflags & ~mask;
 115
 116        /*
 117         * The IMMUTABLE and APPEND_ONLY flags can only be changed by
 118         * the relevant capability.
 119         */
 120        status = -EPERM;
 121        if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
 122                (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
 123                if (!capable(CAP_LINUX_IMMUTABLE))
 124                        goto bail_unlock;
 125        }
 126
 127        ocfs2_inode->ip_attr = flags;
 128        ocfs2_set_inode_flags(inode);
 129
 130        status = ocfs2_mark_inode_dirty(handle, inode, bh);
 131        if (status < 0)
 132                mlog_errno(status);
 133
 134        ocfs2_commit_trans(osb, handle);
 135bail_unlock:
 136        ocfs2_inode_unlock(inode, 1);
 137bail:
 138        mutex_unlock(&inode->i_mutex);
 139
 140        brelse(bh);
 141
 142        return status;
 143}
 144
 145int ocfs2_info_handle_blocksize(struct inode *inode,
 146                                struct ocfs2_info_request __user *req)
 147{
 148        int status = -EFAULT;
 149        struct ocfs2_info_blocksize oib;
 150
 151        if (o2info_from_user(oib, req))
 152                goto bail;
 153
 154        oib.ib_blocksize = inode->i_sb->s_blocksize;
 155
 156        o2info_set_request_filled(oib);
 157
 158        if (o2info_to_user(oib, req))
 159                goto bail;
 160
 161        status = 0;
 162bail:
 163        if (status)
 164                o2info_set_request_error(oib, req);
 165
 166        return status;
 167}
 168
 169int ocfs2_info_handle_clustersize(struct inode *inode,
 170                                  struct ocfs2_info_request __user *req)
 171{
 172        int status = -EFAULT;
 173        struct ocfs2_info_clustersize oic;
 174        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 175
 176        if (o2info_from_user(oic, req))
 177                goto bail;
 178
 179        oic.ic_clustersize = osb->s_clustersize;
 180
 181        o2info_set_request_filled(oic);
 182
 183        if (o2info_to_user(oic, req))
 184                goto bail;
 185
 186        status = 0;
 187bail:
 188        if (status)
 189                o2info_set_request_error(oic, req);
 190
 191        return status;
 192}
 193
 194int ocfs2_info_handle_maxslots(struct inode *inode,
 195                               struct ocfs2_info_request __user *req)
 196{
 197        int status = -EFAULT;
 198        struct ocfs2_info_maxslots oim;
 199        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 200
 201        if (o2info_from_user(oim, req))
 202                goto bail;
 203
 204        oim.im_max_slots = osb->max_slots;
 205
 206        o2info_set_request_filled(oim);
 207
 208        if (o2info_to_user(oim, req))
 209                goto bail;
 210
 211        status = 0;
 212bail:
 213        if (status)
 214                o2info_set_request_error(oim, req);
 215
 216        return status;
 217}
 218
 219int ocfs2_info_handle_label(struct inode *inode,
 220                            struct ocfs2_info_request __user *req)
 221{
 222        int status = -EFAULT;
 223        struct ocfs2_info_label oil;
 224        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 225
 226        if (o2info_from_user(oil, req))
 227                goto bail;
 228
 229        memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
 230
 231        o2info_set_request_filled(oil);
 232
 233        if (o2info_to_user(oil, req))
 234                goto bail;
 235
 236        status = 0;
 237bail:
 238        if (status)
 239                o2info_set_request_error(oil, req);
 240
 241        return status;
 242}
 243
 244int ocfs2_info_handle_uuid(struct inode *inode,
 245                           struct ocfs2_info_request __user *req)
 246{
 247        int status = -EFAULT;
 248        struct ocfs2_info_uuid oiu;
 249        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 250
 251        if (o2info_from_user(oiu, req))
 252                goto bail;
 253
 254        memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
 255
 256        o2info_set_request_filled(oiu);
 257
 258        if (o2info_to_user(oiu, req))
 259                goto bail;
 260
 261        status = 0;
 262bail:
 263        if (status)
 264                o2info_set_request_error(oiu, req);
 265
 266        return status;
 267}
 268
 269int ocfs2_info_handle_fs_features(struct inode *inode,
 270                                  struct ocfs2_info_request __user *req)
 271{
 272        int status = -EFAULT;
 273        struct ocfs2_info_fs_features oif;
 274        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 275
 276        if (o2info_from_user(oif, req))
 277                goto bail;
 278
 279        oif.if_compat_features = osb->s_feature_compat;
 280        oif.if_incompat_features = osb->s_feature_incompat;
 281        oif.if_ro_compat_features = osb->s_feature_ro_compat;
 282
 283        o2info_set_request_filled(oif);
 284
 285        if (o2info_to_user(oif, req))
 286                goto bail;
 287
 288        status = 0;
 289bail:
 290        if (status)
 291                o2info_set_request_error(oif, req);
 292
 293        return status;
 294}
 295
 296int ocfs2_info_handle_journal_size(struct inode *inode,
 297                                   struct ocfs2_info_request __user *req)
 298{
 299        int status = -EFAULT;
 300        struct ocfs2_info_journal_size oij;
 301        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 302
 303        if (o2info_from_user(oij, req))
 304                goto bail;
 305
 306        oij.ij_journal_size = osb->journal->j_inode->i_size;
 307
 308        o2info_set_request_filled(oij);
 309
 310        if (o2info_to_user(oij, req))
 311                goto bail;
 312
 313        status = 0;
 314bail:
 315        if (status)
 316                o2info_set_request_error(oij, req);
 317
 318        return status;
 319}
 320
 321int ocfs2_info_handle_unknown(struct inode *inode,
 322                              struct ocfs2_info_request __user *req)
 323{
 324        int status = -EFAULT;
 325        struct ocfs2_info_request oir;
 326
 327        if (o2info_from_user(oir, req))
 328                goto bail;
 329
 330        o2info_clear_request_filled(oir);
 331
 332        if (o2info_to_user(oir, req))
 333                goto bail;
 334
 335        status = 0;
 336bail:
 337        if (status)
 338                o2info_set_request_error(oir, req);
 339
 340        return status;
 341}
 342
 343/*
 344 * Validate and distinguish OCFS2_IOC_INFO requests.
 345 *
 346 * - validate the magic number.
 347 * - distinguish different requests.
 348 * - validate size of different requests.
 349 */
 350int ocfs2_info_handle_request(struct inode *inode,
 351                              struct ocfs2_info_request __user *req)
 352{
 353        int status = -EFAULT;
 354        struct ocfs2_info_request oir;
 355
 356        if (o2info_from_user(oir, req))
 357                goto bail;
 358
 359        status = -EINVAL;
 360        if (oir.ir_magic != OCFS2_INFO_MAGIC)
 361                goto bail;
 362
 363        switch (oir.ir_code) {
 364        case OCFS2_INFO_BLOCKSIZE:
 365                if (oir.ir_size == sizeof(struct ocfs2_info_blocksize))
 366                        status = ocfs2_info_handle_blocksize(inode, req);
 367                break;
 368        case OCFS2_INFO_CLUSTERSIZE:
 369                if (oir.ir_size == sizeof(struct ocfs2_info_clustersize))
 370                        status = ocfs2_info_handle_clustersize(inode, req);
 371                break;
 372        case OCFS2_INFO_MAXSLOTS:
 373                if (oir.ir_size == sizeof(struct ocfs2_info_maxslots))
 374                        status = ocfs2_info_handle_maxslots(inode, req);
 375                break;
 376        case OCFS2_INFO_LABEL:
 377                if (oir.ir_size == sizeof(struct ocfs2_info_label))
 378                        status = ocfs2_info_handle_label(inode, req);
 379                break;
 380        case OCFS2_INFO_UUID:
 381                if (oir.ir_size == sizeof(struct ocfs2_info_uuid))
 382                        status = ocfs2_info_handle_uuid(inode, req);
 383                break;
 384        case OCFS2_INFO_FS_FEATURES:
 385                if (oir.ir_size == sizeof(struct ocfs2_info_fs_features))
 386                        status = ocfs2_info_handle_fs_features(inode, req);
 387                break;
 388        case OCFS2_INFO_JOURNAL_SIZE:
 389                if (oir.ir_size == sizeof(struct ocfs2_info_journal_size))
 390                        status = ocfs2_info_handle_journal_size(inode, req);
 391                break;
 392        default:
 393                status = ocfs2_info_handle_unknown(inode, req);
 394                break;
 395        }
 396
 397bail:
 398        return status;
 399}
 400
 401int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx,
 402                          u64 *req_addr, int compat_flag)
 403{
 404        int status = -EFAULT;
 405        u64 __user *bp = NULL;
 406
 407        if (compat_flag) {
 408#ifdef CONFIG_COMPAT
 409                /*
 410                 * pointer bp stores the base address of a pointers array,
 411                 * which collects all addresses of separate request.
 412                 */
 413                bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests);
 414#else
 415                BUG();
 416#endif
 417        } else
 418                bp = (u64 __user *)(unsigned long)(info->oi_requests);
 419
 420        if (o2info_from_user(*req_addr, bp + idx))
 421                goto bail;
 422
 423        status = 0;
 424bail:
 425        return status;
 426}
 427
 428/*
 429 * OCFS2_IOC_INFO handles an array of requests passed from userspace.
 430 *
 431 * ocfs2_info_handle() recevies a large info aggregation, grab and
 432 * validate the request count from header, then break it into small
 433 * pieces, later specific handlers can handle them one by one.
 434 *
 435 * Idea here is to make each separate request small enough to ensure
 436 * a better backward&forward compatibility, since a small piece of
 437 * request will be less likely to be broken if disk layout get changed.
 438 */
 439int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info,
 440                      int compat_flag)
 441{
 442        int i, status = 0;
 443        u64 req_addr;
 444        struct ocfs2_info_request __user *reqp;
 445
 446        if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) ||
 447            (!info->oi_requests)) {
 448                status = -EINVAL;
 449                goto bail;
 450        }
 451
 452        for (i = 0; i < info->oi_count; i++) {
 453
 454                status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag);
 455                if (status)
 456                        break;
 457
 458                reqp = (struct ocfs2_info_request *)(unsigned long)req_addr;
 459                if (!reqp) {
 460                        status = -EINVAL;
 461                        goto bail;
 462                }
 463
 464                status = ocfs2_info_handle_request(inode, reqp);
 465                if (status)
 466                        break;
 467        }
 468
 469bail:
 470        return status;
 471}
 472
 473long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 474{
 475        struct inode *inode = filp->f_path.dentry->d_inode;
 476        unsigned int flags;
 477        int new_clusters;
 478        int status;
 479        struct ocfs2_space_resv sr;
 480        struct ocfs2_new_group_input input;
 481        struct reflink_arguments args;
 482        const char *old_path, *new_path;
 483        bool preserve;
 484        struct ocfs2_info info;
 485
 486        switch (cmd) {
 487        case OCFS2_IOC_GETFLAGS:
 488                status = ocfs2_get_inode_attr(inode, &flags);
 489                if (status < 0)
 490                        return status;
 491
 492                flags &= OCFS2_FL_VISIBLE;
 493                return put_user(flags, (int __user *) arg);
 494        case OCFS2_IOC_SETFLAGS:
 495                if (get_user(flags, (int __user *) arg))
 496                        return -EFAULT;
 497
 498                status = mnt_want_write(filp->f_path.mnt);
 499                if (status)
 500                        return status;
 501                status = ocfs2_set_inode_attr(inode, flags,
 502                        OCFS2_FL_MODIFIABLE);
 503                mnt_drop_write(filp->f_path.mnt);
 504                return status;
 505        case OCFS2_IOC_RESVSP:
 506        case OCFS2_IOC_RESVSP64:
 507        case OCFS2_IOC_UNRESVSP:
 508        case OCFS2_IOC_UNRESVSP64:
 509                if (copy_from_user(&sr, (int __user *) arg, sizeof(sr)))
 510                        return -EFAULT;
 511
 512                return ocfs2_change_file_space(filp, cmd, &sr);
 513        case OCFS2_IOC_GROUP_EXTEND:
 514                if (!capable(CAP_SYS_RESOURCE))
 515                        return -EPERM;
 516
 517                if (get_user(new_clusters, (int __user *)arg))
 518                        return -EFAULT;
 519
 520                return ocfs2_group_extend(inode, new_clusters);
 521        case OCFS2_IOC_GROUP_ADD:
 522        case OCFS2_IOC_GROUP_ADD64:
 523                if (!capable(CAP_SYS_RESOURCE))
 524                        return -EPERM;
 525
 526                if (copy_from_user(&input, (int __user *) arg, sizeof(input)))
 527                        return -EFAULT;
 528
 529                return ocfs2_group_add(inode, &input);
 530        case OCFS2_IOC_REFLINK:
 531                if (copy_from_user(&args, (struct reflink_arguments *)arg,
 532                                   sizeof(args)))
 533                        return -EFAULT;
 534                old_path = (const char *)(unsigned long)args.old_path;
 535                new_path = (const char *)(unsigned long)args.new_path;
 536                preserve = (args.preserve != 0);
 537
 538                return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
 539        case OCFS2_IOC_INFO:
 540                if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
 541                                   sizeof(struct ocfs2_info)))
 542                        return -EFAULT;
 543
 544                return ocfs2_info_handle(inode, &info, 0);
 545        default:
 546                return -ENOTTY;
 547        }
 548}
 549
 550#ifdef CONFIG_COMPAT
 551long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 552{
 553        bool preserve;
 554        struct reflink_arguments args;
 555        struct inode *inode = file->f_path.dentry->d_inode;
 556        struct ocfs2_info info;
 557
 558        switch (cmd) {
 559        case OCFS2_IOC32_GETFLAGS:
 560                cmd = OCFS2_IOC_GETFLAGS;
 561                break;
 562        case OCFS2_IOC32_SETFLAGS:
 563                cmd = OCFS2_IOC_SETFLAGS;
 564                break;
 565        case OCFS2_IOC_RESVSP:
 566        case OCFS2_IOC_RESVSP64:
 567        case OCFS2_IOC_UNRESVSP:
 568        case OCFS2_IOC_UNRESVSP64:
 569        case OCFS2_IOC_GROUP_EXTEND:
 570        case OCFS2_IOC_GROUP_ADD:
 571        case OCFS2_IOC_GROUP_ADD64:
 572                break;
 573        case OCFS2_IOC_REFLINK:
 574                if (copy_from_user(&args, (struct reflink_arguments *)arg,
 575                                   sizeof(args)))
 576                        return -EFAULT;
 577                preserve = (args.preserve != 0);
 578
 579                return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path),
 580                                           compat_ptr(args.new_path), preserve);
 581        case OCFS2_IOC_INFO:
 582                if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
 583                                   sizeof(struct ocfs2_info)))
 584                        return -EFAULT;
 585
 586                return ocfs2_info_handle(inode, &info, 1);
 587        default:
 588                return -ENOIOCTLCMD;
 589        }
 590
 591        return ocfs2_ioctl(file, cmd, arg);
 592}
 593#endif
 594