linux/drivers/mtd/ubi/cdev.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) International Business Machines Corp., 2006
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  12 * the GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17 *
  18 * Author: Artem Bityutskiy (Битюцкий Артём)
  19 */
  20
  21/*
  22 * This file includes implementation of UBI character device operations.
  23 *
  24 * There are two kinds of character devices in UBI: UBI character devices and
  25 * UBI volume character devices. UBI character devices allow users to
  26 * manipulate whole volumes: create, remove, and re-size them. Volume character
  27 * devices provide volume I/O capabilities.
  28 *
  29 * Major and minor numbers are assigned dynamically to both UBI and volume
  30 * character devices.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/stat.h>
  35#include <linux/ioctl.h>
  36#include <linux/capability.h>
  37#include <mtd/ubi-user.h>
  38#include <asm/uaccess.h>
  39#include <asm/div64.h>
  40#include "ubi.h"
  41
  42/*
  43 * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
  44 * logical eraseblock erase is a debug-only feature).
  45 */
  46#define UBI_CDEV_IOC_MAX_SEQ 2
  47#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
  48#define VOL_CDEV_IOC_MAX_SEQ 1
  49#else
  50#define VOL_CDEV_IOC_MAX_SEQ 2
  51#endif
  52
  53/**
  54 * major_to_device - get UBI device object by character device major number.
  55 * @major: major number
  56 *
  57 * This function returns a pointer to the UBI device object.
  58 */
  59static struct ubi_device *major_to_device(int major)
  60{
  61        int i;
  62
  63        for (i = 0; i < ubi_devices_cnt; i++)
  64                if (ubi_devices[i] && ubi_devices[i]->major == major)
  65                        return ubi_devices[i];
  66        BUG();
  67        return NULL;
  68}
  69
  70/**
  71 * get_exclusive - get exclusive access to an UBI volume.
  72 * @desc: volume descriptor
  73 *
  74 * This function changes UBI volume open mode to "exclusive". Returns previous
  75 * mode value (positive integer) in case of success and a negative error code
  76 * in case of failure.
  77 */
  78static int get_exclusive(struct ubi_volume_desc *desc)
  79{
  80        int users, err;
  81        struct ubi_volume *vol = desc->vol;
  82
  83        spin_lock(&vol->ubi->volumes_lock);
  84        users = vol->readers + vol->writers + vol->exclusive;
  85        ubi_assert(users > 0);
  86        if (users > 1) {
  87                dbg_err("%d users for volume %d", users, vol->vol_id);
  88                err = -EBUSY;
  89        } else {
  90                vol->readers = vol->writers = 0;
  91                vol->exclusive = 1;
  92                err = desc->mode;
  93                desc->mode = UBI_EXCLUSIVE;
  94        }
  95        spin_unlock(&vol->ubi->volumes_lock);
  96
  97        return err;
  98}
  99
 100/**
 101 * revoke_exclusive - revoke exclusive mode.
 102 * @desc: volume descriptor
 103 * @mode: new mode to switch to
 104 */
 105static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
 106{
 107        struct ubi_volume *vol = desc->vol;
 108
 109        spin_lock(&vol->ubi->volumes_lock);
 110        ubi_assert(vol->readers == 0 && vol->writers == 0);
 111        ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
 112        vol->exclusive = 0;
 113        if (mode == UBI_READONLY)
 114                vol->readers = 1;
 115        else if (mode == UBI_READWRITE)
 116                vol->writers = 1;
 117        else
 118                vol->exclusive = 1;
 119        spin_unlock(&vol->ubi->volumes_lock);
 120
 121        desc->mode = mode;
 122}
 123
 124static int vol_cdev_open(struct inode *inode, struct file *file)
 125{
 126        struct ubi_volume_desc *desc;
 127        const struct ubi_device *ubi = major_to_device(imajor(inode));
 128        int vol_id = iminor(inode) - 1;
 129        int mode;
 130
 131        if (file->f_mode & FMODE_WRITE)
 132                mode = UBI_READWRITE;
 133        else
 134                mode = UBI_READONLY;
 135
 136        dbg_msg("open volume %d, mode %d", vol_id, mode);
 137
 138        desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
 139        if (IS_ERR(desc))
 140                return PTR_ERR(desc);
 141
 142        file->private_data = desc;
 143        return 0;
 144}
 145
 146static int vol_cdev_release(struct inode *inode, struct file *file)
 147{
 148        struct ubi_volume_desc *desc = file->private_data;
 149        struct ubi_volume *vol = desc->vol;
 150
 151        dbg_msg("release volume %d, mode %d", vol->vol_id, desc->mode);
 152
 153        if (vol->updating) {
 154                ubi_warn("update of volume %d not finished, volume is damaged",
 155                         vol->vol_id);
 156                vol->updating = 0;
 157                vfree(vol->upd_buf);
 158        }
 159
 160        ubi_close_volume(desc);
 161        return 0;
 162}
 163
 164static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
 165{
 166        struct ubi_volume_desc *desc = file->private_data;
 167        struct ubi_volume *vol = desc->vol;
 168        loff_t new_offset;
 169
 170        if (vol->updating) {
 171                 /* Update is in progress, seeking is prohibited */
 172                dbg_err("updating");
 173                return -EBUSY;
 174        }
 175
 176        switch (origin) {
 177        case 0: /* SEEK_SET */
 178                new_offset = offset;
 179                break;
 180        case 1: /* SEEK_CUR */
 181                new_offset = file->f_pos + offset;
 182                break;
 183        case 2: /* SEEK_END */
 184                new_offset = vol->used_bytes + offset;
 185                break;
 186        default:
 187                return -EINVAL;
 188        }
 189
 190        if (new_offset < 0 || new_offset > vol->used_bytes) {
 191                dbg_err("bad seek %lld", new_offset);
 192                return -EINVAL;
 193        }
 194
 195        dbg_msg("seek volume %d, offset %lld, origin %d, new offset %lld",
 196                vol->vol_id, offset, origin, new_offset);
 197
 198        file->f_pos = new_offset;
 199        return new_offset;
 200}
 201
 202static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
 203                             loff_t *offp)
 204{
 205        struct ubi_volume_desc *desc = file->private_data;
 206        struct ubi_volume *vol = desc->vol;
 207        struct ubi_device *ubi = vol->ubi;
 208        int err, lnum, off, len,  vol_id = desc->vol->vol_id, tbuf_size;
 209        size_t count_save = count;
 210        void *tbuf;
 211        uint64_t tmp;
 212
 213        dbg_msg("read %zd bytes from offset %lld of volume %d",
 214                count, *offp, vol_id);
 215
 216        if (vol->updating) {
 217                dbg_err("updating");
 218                return -EBUSY;
 219        }
 220        if (vol->upd_marker) {
 221                dbg_err("damaged volume, update marker is set");
 222                return -EBADF;
 223        }
 224        if (*offp == vol->used_bytes || count == 0)
 225                return 0;
 226
 227        if (vol->corrupted)
 228                dbg_msg("read from corrupted volume %d", vol_id);
 229
 230        if (*offp + count > vol->used_bytes)
 231                count_save = count = vol->used_bytes - *offp;
 232
 233        tbuf_size = vol->usable_leb_size;
 234        if (count < tbuf_size)
 235                tbuf_size = ALIGN(count, ubi->min_io_size);
 236        tbuf = vmalloc(tbuf_size);
 237        if (!tbuf)
 238                return -ENOMEM;
 239
 240        len = count > tbuf_size ? tbuf_size : count;
 241
 242        tmp = *offp;
 243        off = do_div(tmp, vol->usable_leb_size);
 244        lnum = tmp;
 245
 246        do {
 247                cond_resched();
 248
 249                if (off + len >= vol->usable_leb_size)
 250                        len = vol->usable_leb_size - off;
 251
 252                err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0);
 253                if (err)
 254                        break;
 255
 256                off += len;
 257                if (off == vol->usable_leb_size) {
 258                        lnum += 1;
 259                        off -= vol->usable_leb_size;
 260                }
 261
 262                count -= len;
 263                *offp += len;
 264
 265                err = copy_to_user(buf, tbuf, len);
 266                if (err) {
 267                        err = -EFAULT;
 268                        break;
 269                }
 270
 271                buf += len;
 272                len = count > tbuf_size ? tbuf_size : count;
 273        } while (count);
 274
 275        vfree(tbuf);
 276        return err ? err : count_save - count;
 277}
 278
 279#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
 280
 281/*
 282 * This function allows to directly write to dynamic UBI volumes, without
 283 * issuing the volume update operation. Available only as a debugging feature.
 284 * Very useful for testing UBI.
 285 */
 286static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
 287                                     size_t count, loff_t *offp)
 288{
 289        struct ubi_volume_desc *desc = file->private_data;
 290        struct ubi_volume *vol = desc->vol;
 291        struct ubi_device *ubi = vol->ubi;
 292        int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0;
 293        size_t count_save = count;
 294        char *tbuf;
 295        uint64_t tmp;
 296
 297        dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
 298                count, *offp, desc->vol->vol_id);
 299
 300        if (vol->vol_type == UBI_STATIC_VOLUME)
 301                return -EROFS;
 302
 303        tmp = *offp;
 304        off = do_div(tmp, vol->usable_leb_size);
 305        lnum = tmp;
 306
 307        if (off % ubi->min_io_size) {
 308                dbg_err("unaligned position");
 309                return -EINVAL;
 310        }
 311
 312        if (*offp + count > vol->used_bytes)
 313                count_save = count = vol->used_bytes - *offp;
 314
 315        /* We can write only in fractions of the minimum I/O unit */
 316        if (count % ubi->min_io_size) {
 317                dbg_err("unaligned write length");
 318                return -EINVAL;
 319        }
 320
 321        tbuf_size = vol->usable_leb_size;
 322        if (count < tbuf_size)
 323                tbuf_size = ALIGN(count, ubi->min_io_size);
 324        tbuf = vmalloc(tbuf_size);
 325        if (!tbuf)
 326                return -ENOMEM;
 327
 328        len = count > tbuf_size ? tbuf_size : count;
 329
 330        while (count) {
 331                cond_resched();
 332
 333                if (off + len >= vol->usable_leb_size)
 334                        len = vol->usable_leb_size - off;
 335
 336                err = copy_from_user(tbuf, buf, len);
 337                if (err) {
 338                        err = -EFAULT;
 339                        break;
 340                }
 341
 342                err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
 343                                        UBI_UNKNOWN);
 344                if (err)
 345                        break;
 346
 347                off += len;
 348                if (off == vol->usable_leb_size) {
 349                        lnum += 1;
 350                        off -= vol->usable_leb_size;
 351                }
 352
 353                count -= len;
 354                *offp += len;
 355                buf += len;
 356                len = count > tbuf_size ? tbuf_size : count;
 357        }
 358
 359        vfree(tbuf);
 360        return err ? err : count_save - count;
 361}
 362
 363#else
 364#define vol_cdev_direct_write(file, buf, count, offp) -EPERM
 365#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */
 366
 367static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
 368                              size_t count, loff_t *offp)
 369{
 370        int err = 0;
 371        struct ubi_volume_desc *desc = file->private_data;
 372        struct ubi_volume *vol = desc->vol;
 373        struct ubi_device *ubi = vol->ubi;
 374
 375        if (!vol->updating)
 376                return vol_cdev_direct_write(file, buf, count, offp);
 377
 378        err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
 379        if (err < 0) {
 380                ubi_err("cannot write %zd bytes of update data", count);
 381                return err;
 382        }
 383
 384        if (err) {
 385                /*
 386                 * Update is finished, @err contains number of actually written
 387                 * bytes now.
 388                 */
 389                count = err;
 390
 391                err = ubi_check_volume(ubi, vol->vol_id);
 392                if (err < 0)
 393                        return err;
 394
 395                if (err) {
 396                        ubi_warn("volume %d on UBI device %d is corrupted",
 397                                 vol->vol_id, ubi->ubi_num);
 398                        vol->corrupted = 1;
 399                }
 400                vol->checked = 1;
 401                ubi_gluebi_updated(vol);
 402                revoke_exclusive(desc, UBI_READWRITE);
 403        }
 404
 405        *offp += count;
 406        return count;
 407}
 408
 409static int vol_cdev_ioctl(struct inode *inode, struct file *file,
 410                          unsigned int cmd, unsigned long arg)
 411{
 412        int err = 0;
 413        struct ubi_volume_desc *desc = file->private_data;
 414        struct ubi_volume *vol = desc->vol;
 415        struct ubi_device *ubi = vol->ubi;
 416        void __user *argp = (void __user *)arg;
 417
 418        switch (cmd) {
 419        /* Volume update command */
 420        case UBI_IOCVOLUP:
 421        {
 422                int64_t bytes, rsvd_bytes;
 423
 424                if (!capable(CAP_SYS_RESOURCE)) {
 425                        err = -EPERM;
 426                        break;
 427                }
 428
 429                err = copy_from_user(&bytes, argp, sizeof(int64_t));
 430                if (err) {
 431                        err = -EFAULT;
 432                        break;
 433                }
 434
 435                if (desc->mode == UBI_READONLY) {
 436                        err = -EROFS;
 437                        break;
 438                }
 439
 440                rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad);
 441                if (bytes < 0 || bytes > rsvd_bytes) {
 442                        err = -EINVAL;
 443                        break;
 444                }
 445
 446                err = get_exclusive(desc);
 447                if (err < 0)
 448                        break;
 449
 450                err = ubi_start_update(ubi, vol->vol_id, bytes);
 451                if (bytes == 0)
 452                        revoke_exclusive(desc, UBI_READWRITE);
 453
 454                file->f_pos = 0;
 455                break;
 456        }
 457
 458#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
 459        /* Logical eraseblock erasure command */
 460        case UBI_IOCEBER:
 461        {
 462                int32_t lnum;
 463
 464                err = get_user(lnum, (__user int32_t *)argp);
 465                if (err) {
 466                        err = -EFAULT;
 467                        break;
 468                }
 469
 470                if (desc->mode == UBI_READONLY) {
 471                        err = -EROFS;
 472                        break;
 473                }
 474
 475                if (lnum < 0 || lnum >= vol->reserved_pebs) {
 476                        err = -EINVAL;
 477                        break;
 478                }
 479
 480                if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
 481                        err = -EROFS;
 482                        break;
 483                }
 484
 485                dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
 486                err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum);
 487                if (err)
 488                        break;
 489
 490                err = ubi_wl_flush(ubi);
 491                break;
 492        }
 493#endif
 494
 495        default:
 496                err = -ENOTTY;
 497                break;
 498        }
 499
 500        return err;
 501}
 502
 503/**
 504 * verify_mkvol_req - verify volume creation request.
 505 * @ubi: UBI device description object
 506 * @req: the request to check
 507 *
 508 * This function zero if the request is correct, and %-EINVAL if not.
 509 */
 510static int verify_mkvol_req(const struct ubi_device *ubi,
 511                            const struct ubi_mkvol_req *req)
 512{
 513        int n, err = -EINVAL;
 514
 515        if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
 516            req->name_len < 0)
 517                goto bad;
 518
 519        if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
 520            req->vol_id != UBI_VOL_NUM_AUTO)
 521                goto bad;
 522
 523        if (req->alignment == 0)
 524                goto bad;
 525
 526        if (req->bytes == 0)
 527                goto bad;
 528
 529        if (req->vol_type != UBI_DYNAMIC_VOLUME &&
 530            req->vol_type != UBI_STATIC_VOLUME)
 531                goto bad;
 532
 533        if (req->alignment > ubi->leb_size)
 534                goto bad;
 535
 536        n = req->alignment % ubi->min_io_size;
 537        if (req->alignment != 1 && n)
 538                goto bad;
 539
 540        if (req->name_len > UBI_VOL_NAME_MAX) {
 541                err = -ENAMETOOLONG;
 542                goto bad;
 543        }
 544
 545        return 0;
 546
 547bad:
 548        dbg_err("bad volume creation request");
 549        ubi_dbg_dump_mkvol_req(req);
 550        return err;
 551}
 552
 553/**
 554 * verify_rsvol_req - verify volume re-size request.
 555 * @ubi: UBI device description object
 556 * @req: the request to check
 557 *
 558 * This function returns zero if the request is correct, and %-EINVAL if not.
 559 */
 560static int verify_rsvol_req(const struct ubi_device *ubi,
 561                            const struct ubi_rsvol_req *req)
 562{
 563        if (req->bytes <= 0)
 564                return -EINVAL;
 565
 566        if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)
 567                return -EINVAL;
 568
 569        return 0;
 570}
 571
 572static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 573                          unsigned int cmd, unsigned long arg)
 574{
 575        int err = 0;
 576        struct ubi_device *ubi;
 577        struct ubi_volume_desc *desc;
 578        void __user *argp = (void __user *)arg;
 579
 580        if (!capable(CAP_SYS_RESOURCE))
 581                return -EPERM;
 582
 583        ubi = major_to_device(imajor(inode));
 584        if (IS_ERR(ubi))
 585                return PTR_ERR(ubi);
 586
 587        switch (cmd) {
 588        /* Create volume command */
 589        case UBI_IOCMKVOL:
 590        {
 591                struct ubi_mkvol_req req;
 592
 593                dbg_msg("create volume");
 594                err = copy_from_user(&req, argp,
 595                                       sizeof(struct ubi_mkvol_req));
 596                if (err) {
 597                        err = -EFAULT;
 598                        break;
 599                }
 600
 601                err = verify_mkvol_req(ubi, &req);
 602                if (err)
 603                        break;
 604
 605                req.name[req.name_len] = '\0';
 606
 607                err = ubi_create_volume(ubi, &req);
 608                if (err)
 609                        break;
 610
 611                err = put_user(req.vol_id, (__user int32_t *)argp);
 612                if (err)
 613                        err = -EFAULT;
 614
 615                break;
 616        }
 617
 618        /* Remove volume command */
 619        case UBI_IOCRMVOL:
 620        {
 621                int vol_id;
 622
 623                dbg_msg("remove volume");
 624                err = get_user(vol_id, (__user int32_t *)argp);
 625                if (err) {
 626                        err = -EFAULT;
 627                        break;
 628                }
 629
 630                desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
 631                if (IS_ERR(desc)) {
 632                        err = PTR_ERR(desc);
 633                        break;
 634                }
 635
 636                err = ubi_remove_volume(desc);
 637                if (err)
 638                        ubi_close_volume(desc);
 639
 640                break;
 641        }
 642
 643        /* Re-size volume command */
 644        case UBI_IOCRSVOL:
 645        {
 646                int pebs;
 647                uint64_t tmp;
 648                struct ubi_rsvol_req req;
 649
 650                dbg_msg("re-size volume");
 651                err = copy_from_user(&req, argp,
 652                                       sizeof(struct ubi_rsvol_req));
 653                if (err) {
 654                        err = -EFAULT;
 655                        break;
 656                }
 657
 658                err = verify_rsvol_req(ubi, &req);
 659                if (err)
 660                        break;
 661
 662                desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);
 663                if (IS_ERR(desc)) {
 664                        err = PTR_ERR(desc);
 665                        break;
 666                }
 667
 668                tmp = req.bytes;
 669                pebs = !!do_div(tmp, desc->vol->usable_leb_size);
 670                pebs += tmp;
 671
 672                err = ubi_resize_volume(desc, pebs);
 673                ubi_close_volume(desc);
 674                break;
 675        }
 676
 677        default:
 678                err = -ENOTTY;
 679                break;
 680        }
 681
 682        return err;
 683}
 684
 685/* UBI character device operations */
 686struct file_operations ubi_cdev_operations = {
 687        .owner = THIS_MODULE,
 688        .ioctl = ubi_cdev_ioctl,
 689        .llseek = no_llseek,
 690};
 691
 692/* UBI volume character device operations */
 693struct file_operations ubi_vol_cdev_operations = {
 694        .owner   = THIS_MODULE,
 695        .open    = vol_cdev_open,
 696        .release = vol_cdev_release,
 697        .llseek  = vol_cdev_llseek,
 698        .read    = vol_cdev_read,
 699        .write   = vol_cdev_write,
 700        .ioctl   = vol_cdev_ioctl,
 701};
 702