linux/fs/exofs/super.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005, 2006
   3 * Avishay Traeger (avishay@gmail.com)
   4 * Copyright (C) 2008, 2009
   5 * Boaz Harrosh <bharrosh@panasas.com>
   6 *
   7 * Copyrights for code taken from ext2:
   8 *     Copyright (C) 1992, 1993, 1994, 1995
   9 *     Remy Card (card@masi.ibp.fr)
  10 *     Laboratoire MASI - Institut Blaise Pascal
  11 *     Universite Pierre et Marie Curie (Paris VI)
  12 *     from
  13 *     linux/fs/minix/inode.c
  14 *     Copyright (C) 1991, 1992  Linus Torvalds
  15 *
  16 * This file is part of exofs.
  17 *
  18 * exofs is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation.  Since it is based on ext2, and the only
  21 * valid version of GPL for the Linux kernel is version 2, the only valid
  22 * version of GPL for exofs is version 2.
  23 *
  24 * exofs is distributed in the hope that it will be useful,
  25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27 * GNU General Public License for more details.
  28 *
  29 * You should have received a copy of the GNU General Public License
  30 * along with exofs; if not, write to the Free Software
  31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  32 */
  33
  34#include <linux/smp_lock.h>
  35#include <linux/string.h>
  36#include <linux/parser.h>
  37#include <linux/vfs.h>
  38#include <linux/random.h>
  39#include <linux/exportfs.h>
  40
  41#include "exofs.h"
  42
  43/******************************************************************************
  44 * MOUNT OPTIONS
  45 *****************************************************************************/
  46
  47/*
  48 * struct to hold what we get from mount options
  49 */
  50struct exofs_mountopt {
  51        const char *dev_name;
  52        uint64_t pid;
  53        int timeout;
  54};
  55
  56/*
  57 * exofs-specific mount-time options.
  58 */
  59enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
  60
  61/*
  62 * Our mount-time options.  These should ideally be 64-bit unsigned, but the
  63 * kernel's parsing functions do not currently support that.  32-bit should be
  64 * sufficient for most applications now.
  65 */
  66static match_table_t tokens = {
  67        {Opt_pid, "pid=%u"},
  68        {Opt_to, "to=%u"},
  69        {Opt_err, NULL}
  70};
  71
  72/*
  73 * The main option parsing method.  Also makes sure that all of the mandatory
  74 * mount options were set.
  75 */
  76static int parse_options(char *options, struct exofs_mountopt *opts)
  77{
  78        char *p;
  79        substring_t args[MAX_OPT_ARGS];
  80        int option;
  81        bool s_pid = false;
  82
  83        EXOFS_DBGMSG("parse_options %s\n", options);
  84        /* defaults */
  85        memset(opts, 0, sizeof(*opts));
  86        opts->timeout = BLK_DEFAULT_SG_TIMEOUT;
  87
  88        while ((p = strsep(&options, ",")) != NULL) {
  89                int token;
  90                char str[32];
  91
  92                if (!*p)
  93                        continue;
  94
  95                token = match_token(p, tokens, args);
  96                switch (token) {
  97                case Opt_pid:
  98                        if (0 == match_strlcpy(str, &args[0], sizeof(str)))
  99                                return -EINVAL;
 100                        opts->pid = simple_strtoull(str, NULL, 0);
 101                        if (opts->pid < EXOFS_MIN_PID) {
 102                                EXOFS_ERR("Partition ID must be >= %u",
 103                                          EXOFS_MIN_PID);
 104                                return -EINVAL;
 105                        }
 106                        s_pid = 1;
 107                        break;
 108                case Opt_to:
 109                        if (match_int(&args[0], &option))
 110                                return -EINVAL;
 111                        if (option <= 0) {
 112                                EXOFS_ERR("Timout must be > 0");
 113                                return -EINVAL;
 114                        }
 115                        opts->timeout = option * HZ;
 116                        break;
 117                }
 118        }
 119
 120        if (!s_pid) {
 121                EXOFS_ERR("Need to specify the following options:\n");
 122                EXOFS_ERR("    -o pid=pid_no_to_use\n");
 123                return -EINVAL;
 124        }
 125
 126        return 0;
 127}
 128
 129/******************************************************************************
 130 * INODE CACHE
 131 *****************************************************************************/
 132
 133/*
 134 * Our inode cache.  Isn't it pretty?
 135 */
 136static struct kmem_cache *exofs_inode_cachep;
 137
 138/*
 139 * Allocate an inode in the cache
 140 */
 141static struct inode *exofs_alloc_inode(struct super_block *sb)
 142{
 143        struct exofs_i_info *oi;
 144
 145        oi = kmem_cache_alloc(exofs_inode_cachep, GFP_KERNEL);
 146        if (!oi)
 147                return NULL;
 148
 149        oi->vfs_inode.i_version = 1;
 150        return &oi->vfs_inode;
 151}
 152
 153/*
 154 * Remove an inode from the cache
 155 */
 156static void exofs_destroy_inode(struct inode *inode)
 157{
 158        kmem_cache_free(exofs_inode_cachep, exofs_i(inode));
 159}
 160
 161/*
 162 * Initialize the inode
 163 */
 164static void exofs_init_once(void *foo)
 165{
 166        struct exofs_i_info *oi = foo;
 167
 168        inode_init_once(&oi->vfs_inode);
 169}
 170
 171/*
 172 * Create and initialize the inode cache
 173 */
 174static int init_inodecache(void)
 175{
 176        exofs_inode_cachep = kmem_cache_create("exofs_inode_cache",
 177                                sizeof(struct exofs_i_info), 0,
 178                                SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
 179                                exofs_init_once);
 180        if (exofs_inode_cachep == NULL)
 181                return -ENOMEM;
 182        return 0;
 183}
 184
 185/*
 186 * Destroy the inode cache
 187 */
 188static void destroy_inodecache(void)
 189{
 190        kmem_cache_destroy(exofs_inode_cachep);
 191}
 192
 193/******************************************************************************
 194 * SUPERBLOCK FUNCTIONS
 195 *****************************************************************************/
 196static const struct super_operations exofs_sops;
 197static const struct export_operations exofs_export_ops;
 198
 199/*
 200 * Write the superblock to the OSD
 201 */
 202int exofs_sync_fs(struct super_block *sb, int wait)
 203{
 204        struct exofs_sb_info *sbi;
 205        struct exofs_fscb *fscb;
 206        struct osd_request *or;
 207        struct osd_obj_id obj;
 208        int ret = -ENOMEM;
 209
 210        fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL);
 211        if (!fscb) {
 212                EXOFS_ERR("exofs_write_super: memory allocation failed.\n");
 213                return -ENOMEM;
 214        }
 215
 216        lock_super(sb);
 217        sbi = sb->s_fs_info;
 218        fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
 219        fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
 220        fscb->s_magic = cpu_to_le16(sb->s_magic);
 221        fscb->s_newfs = 0;
 222
 223        or = osd_start_request(sbi->s_dev, GFP_KERNEL);
 224        if (unlikely(!or)) {
 225                EXOFS_ERR("exofs_write_super: osd_start_request failed.\n");
 226                goto out;
 227        }
 228
 229        obj.partition = sbi->s_pid;
 230        obj.id = EXOFS_SUPER_ID;
 231        ret = osd_req_write_kern(or, &obj, 0, fscb, sizeof(*fscb));
 232        if (unlikely(ret)) {
 233                EXOFS_ERR("exofs_write_super: osd_req_write_kern failed.\n");
 234                goto out;
 235        }
 236
 237        ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
 238        if (unlikely(ret)) {
 239                EXOFS_ERR("exofs_write_super: exofs_sync_op failed.\n");
 240                goto out;
 241        }
 242        sb->s_dirt = 0;
 243
 244out:
 245        if (or)
 246                osd_end_request(or);
 247        unlock_super(sb);
 248        kfree(fscb);
 249        return ret;
 250}
 251
 252static void exofs_write_super(struct super_block *sb)
 253{
 254        if (!(sb->s_flags & MS_RDONLY))
 255                exofs_sync_fs(sb, 1);
 256        else
 257                sb->s_dirt = 0;
 258}
 259
 260/*
 261 * This function is called when the vfs is freeing the superblock.  We just
 262 * need to free our own part.
 263 */
 264static void exofs_put_super(struct super_block *sb)
 265{
 266        int num_pend;
 267        struct exofs_sb_info *sbi = sb->s_fs_info;
 268
 269        if (sb->s_dirt)
 270                exofs_write_super(sb);
 271
 272        /* make sure there are no pending commands */
 273        for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0;
 274             num_pend = atomic_read(&sbi->s_curr_pending)) {
 275                wait_queue_head_t wq;
 276                init_waitqueue_head(&wq);
 277                wait_event_timeout(wq,
 278                                  (atomic_read(&sbi->s_curr_pending) == 0),
 279                                  msecs_to_jiffies(100));
 280        }
 281
 282        osduld_put_device(sbi->s_dev);
 283        kfree(sb->s_fs_info);
 284        sb->s_fs_info = NULL;
 285}
 286
 287/*
 288 * Read the superblock from the OSD and fill in the fields
 289 */
 290static int exofs_fill_super(struct super_block *sb, void *data, int silent)
 291{
 292        struct inode *root;
 293        struct exofs_mountopt *opts = data;
 294        struct exofs_sb_info *sbi;      /*extended info                  */
 295        struct exofs_fscb fscb;         /*on-disk superblock info        */
 296        struct osd_request *or = NULL;
 297        struct osd_obj_id obj;
 298        int ret;
 299
 300        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 301        if (!sbi)
 302                return -ENOMEM;
 303        sb->s_fs_info = sbi;
 304
 305        /* use mount options to fill superblock */
 306        sbi->s_dev = osduld_path_lookup(opts->dev_name);
 307        if (IS_ERR(sbi->s_dev)) {
 308                ret = PTR_ERR(sbi->s_dev);
 309                sbi->s_dev = NULL;
 310                goto free_sbi;
 311        }
 312
 313        sbi->s_pid = opts->pid;
 314        sbi->s_timeout = opts->timeout;
 315
 316        /* fill in some other data by hand */
 317        memset(sb->s_id, 0, sizeof(sb->s_id));
 318        strcpy(sb->s_id, "exofs");
 319        sb->s_blocksize = EXOFS_BLKSIZE;
 320        sb->s_blocksize_bits = EXOFS_BLKSHIFT;
 321        sb->s_maxbytes = MAX_LFS_FILESIZE;
 322        atomic_set(&sbi->s_curr_pending, 0);
 323        sb->s_bdev = NULL;
 324        sb->s_dev = 0;
 325
 326        /* read data from on-disk superblock object */
 327        obj.partition = sbi->s_pid;
 328        obj.id = EXOFS_SUPER_ID;
 329        exofs_make_credential(sbi->s_cred, &obj);
 330
 331        or = osd_start_request(sbi->s_dev, GFP_KERNEL);
 332        if (unlikely(!or)) {
 333                if (!silent)
 334                        EXOFS_ERR(
 335                               "exofs_fill_super: osd_start_request failed.\n");
 336                ret = -ENOMEM;
 337                goto free_sbi;
 338        }
 339        ret = osd_req_read_kern(or, &obj, 0, &fscb, sizeof(fscb));
 340        if (unlikely(ret)) {
 341                if (!silent)
 342                        EXOFS_ERR(
 343                               "exofs_fill_super: osd_req_read_kern failed.\n");
 344                ret = -ENOMEM;
 345                goto free_sbi;
 346        }
 347
 348        ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
 349        if (unlikely(ret)) {
 350                if (!silent)
 351                        EXOFS_ERR("exofs_fill_super: exofs_sync_op failed.\n");
 352                ret = -EIO;
 353                goto free_sbi;
 354        }
 355
 356        sb->s_magic = le16_to_cpu(fscb.s_magic);
 357        sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
 358        sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);
 359
 360        /* make sure what we read from the object store is correct */
 361        if (sb->s_magic != EXOFS_SUPER_MAGIC) {
 362                if (!silent)
 363                        EXOFS_ERR("ERROR: Bad magic value\n");
 364                ret = -EINVAL;
 365                goto free_sbi;
 366        }
 367
 368        /* start generation numbers from a random point */
 369        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 370        spin_lock_init(&sbi->s_next_gen_lock);
 371
 372        /* set up operation vectors */
 373        sb->s_op = &exofs_sops;
 374        sb->s_export_op = &exofs_export_ops;
 375        root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF);
 376        if (IS_ERR(root)) {
 377                EXOFS_ERR("ERROR: exofs_iget failed\n");
 378                ret = PTR_ERR(root);
 379                goto free_sbi;
 380        }
 381        sb->s_root = d_alloc_root(root);
 382        if (!sb->s_root) {
 383                iput(root);
 384                EXOFS_ERR("ERROR: get root inode failed\n");
 385                ret = -ENOMEM;
 386                goto free_sbi;
 387        }
 388
 389        if (!S_ISDIR(root->i_mode)) {
 390                dput(sb->s_root);
 391                sb->s_root = NULL;
 392                EXOFS_ERR("ERROR: corrupt root inode (mode = %hd)\n",
 393                       root->i_mode);
 394                ret = -EINVAL;
 395                goto free_sbi;
 396        }
 397
 398        ret = 0;
 399out:
 400        if (or)
 401                osd_end_request(or);
 402        return ret;
 403
 404free_sbi:
 405        osduld_put_device(sbi->s_dev); /* NULL safe */
 406        kfree(sbi);
 407        goto out;
 408}
 409
 410/*
 411 * Set up the superblock (calls exofs_fill_super eventually)
 412 */
 413static int exofs_get_sb(struct file_system_type *type,
 414                          int flags, const char *dev_name,
 415                          void *data, struct vfsmount *mnt)
 416{
 417        struct exofs_mountopt opts;
 418        int ret;
 419
 420        ret = parse_options(data, &opts);
 421        if (ret)
 422                return ret;
 423
 424        opts.dev_name = dev_name;
 425        return get_sb_nodev(type, flags, &opts, exofs_fill_super, mnt);
 426}
 427
 428/*
 429 * Return information about the file system state in the buffer.  This is used
 430 * by the 'df' command, for example.
 431 */
 432static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
 433{
 434        struct super_block *sb = dentry->d_sb;
 435        struct exofs_sb_info *sbi = sb->s_fs_info;
 436        struct osd_obj_id obj = {sbi->s_pid, 0};
 437        struct osd_attr attrs[] = {
 438                ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
 439                        OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
 440                ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION,
 441                        OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)),
 442        };
 443        uint64_t capacity = ULLONG_MAX;
 444        uint64_t used = ULLONG_MAX;
 445        struct osd_request *or;
 446        uint8_t cred_a[OSD_CAP_LEN];
 447        int ret;
 448
 449        /* get used/capacity attributes */
 450        exofs_make_credential(cred_a, &obj);
 451
 452        or = osd_start_request(sbi->s_dev, GFP_KERNEL);
 453        if (unlikely(!or)) {
 454                EXOFS_DBGMSG("exofs_statfs: osd_start_request failed.\n");
 455                return -ENOMEM;
 456        }
 457
 458        osd_req_get_attributes(or, &obj);
 459        osd_req_add_get_attr_list(or, attrs, ARRAY_SIZE(attrs));
 460        ret = exofs_sync_op(or, sbi->s_timeout, cred_a);
 461        if (unlikely(ret))
 462                goto out;
 463
 464        ret = extract_attr_from_req(or, &attrs[0]);
 465        if (likely(!ret))
 466                capacity = get_unaligned_be64(attrs[0].val_ptr);
 467        else
 468                EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n");
 469
 470        ret = extract_attr_from_req(or, &attrs[1]);
 471        if (likely(!ret))
 472                used = get_unaligned_be64(attrs[1].val_ptr);
 473        else
 474                EXOFS_DBGMSG("exofs_statfs: get used-space failed.\n");
 475
 476        /* fill in the stats buffer */
 477        buf->f_type = EXOFS_SUPER_MAGIC;
 478        buf->f_bsize = EXOFS_BLKSIZE;
 479        buf->f_blocks = (capacity >> EXOFS_BLKSHIFT);
 480        buf->f_bfree = ((capacity - used) >> EXOFS_BLKSHIFT);
 481        buf->f_bavail = buf->f_bfree;
 482        buf->f_files = sbi->s_numfiles;
 483        buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles;
 484        buf->f_namelen = EXOFS_NAME_LEN;
 485
 486out:
 487        osd_end_request(or);
 488        return ret;
 489}
 490
 491static const struct super_operations exofs_sops = {
 492        .alloc_inode    = exofs_alloc_inode,
 493        .destroy_inode  = exofs_destroy_inode,
 494        .write_inode    = exofs_write_inode,
 495        .delete_inode   = exofs_delete_inode,
 496        .put_super      = exofs_put_super,
 497        .write_super    = exofs_write_super,
 498        .sync_fs        = exofs_sync_fs,
 499        .statfs         = exofs_statfs,
 500};
 501
 502/******************************************************************************
 503 * EXPORT OPERATIONS
 504 *****************************************************************************/
 505
 506struct dentry *exofs_get_parent(struct dentry *child)
 507{
 508        unsigned long ino = exofs_parent_ino(child);
 509
 510        if (!ino)
 511                return NULL;
 512
 513        return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
 514}
 515
 516static struct inode *exofs_nfs_get_inode(struct super_block *sb,
 517                u64 ino, u32 generation)
 518{
 519        struct inode *inode;
 520
 521        inode = exofs_iget(sb, ino);
 522        if (IS_ERR(inode))
 523                return ERR_CAST(inode);
 524        if (generation && inode->i_generation != generation) {
 525                /* we didn't find the right inode.. */
 526                iput(inode);
 527                return ERR_PTR(-ESTALE);
 528        }
 529        return inode;
 530}
 531
 532static struct dentry *exofs_fh_to_dentry(struct super_block *sb,
 533                                struct fid *fid, int fh_len, int fh_type)
 534{
 535        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
 536                                    exofs_nfs_get_inode);
 537}
 538
 539static struct dentry *exofs_fh_to_parent(struct super_block *sb,
 540                                struct fid *fid, int fh_len, int fh_type)
 541{
 542        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
 543                                    exofs_nfs_get_inode);
 544}
 545
 546static const struct export_operations exofs_export_ops = {
 547        .fh_to_dentry = exofs_fh_to_dentry,
 548        .fh_to_parent = exofs_fh_to_parent,
 549        .get_parent = exofs_get_parent,
 550};
 551
 552/******************************************************************************
 553 * INSMOD/RMMOD
 554 *****************************************************************************/
 555
 556/*
 557 * struct that describes this file system
 558 */
 559static struct file_system_type exofs_type = {
 560        .owner          = THIS_MODULE,
 561        .name           = "exofs",
 562        .get_sb         = exofs_get_sb,
 563        .kill_sb        = generic_shutdown_super,
 564};
 565
 566static int __init init_exofs(void)
 567{
 568        int err;
 569
 570        err = init_inodecache();
 571        if (err)
 572                goto out;
 573
 574        err = register_filesystem(&exofs_type);
 575        if (err)
 576                goto out_d;
 577
 578        return 0;
 579out_d:
 580        destroy_inodecache();
 581out:
 582        return err;
 583}
 584
 585static void __exit exit_exofs(void)
 586{
 587        unregister_filesystem(&exofs_type);
 588        destroy_inodecache();
 589}
 590
 591MODULE_AUTHOR("Avishay Traeger <avishay@gmail.com>");
 592MODULE_DESCRIPTION("exofs");
 593MODULE_LICENSE("GPL");
 594
 595module_init(init_exofs)
 596module_exit(exit_exofs)
 597