linux/fs/ceph/super.c
<<
>>
Prefs
   1
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/backing-dev.h>
   5#include <linux/ctype.h>
   6#include <linux/fs.h>
   7#include <linux/inet.h>
   8#include <linux/in6.h>
   9#include <linux/module.h>
  10#include <linux/mount.h>
  11#include <linux/parser.h>
  12#include <linux/sched.h>
  13#include <linux/seq_file.h>
  14#include <linux/slab.h>
  15#include <linux/statfs.h>
  16#include <linux/string.h>
  17
  18#include "super.h"
  19#include "mds_client.h"
  20
  21#include <linux/ceph/ceph_features.h>
  22#include <linux/ceph/decode.h>
  23#include <linux/ceph/mon_client.h>
  24#include <linux/ceph/auth.h>
  25#include <linux/ceph/debugfs.h>
  26
  27/*
  28 * Ceph superblock operations
  29 *
  30 * Handle the basics of mounting, unmounting.
  31 */
  32
  33/*
  34 * super ops
  35 */
  36static void ceph_put_super(struct super_block *s)
  37{
  38        struct ceph_fs_client *fsc = ceph_sb_to_client(s);
  39
  40        dout("put_super\n");
  41        ceph_mdsc_close_sessions(fsc->mdsc);
  42
  43        /*
  44         * ensure we release the bdi before put_anon_super releases
  45         * the device name.
  46         */
  47        if (s->s_bdi == &fsc->backing_dev_info) {
  48                bdi_unregister(&fsc->backing_dev_info);
  49                s->s_bdi = NULL;
  50        }
  51
  52        return;
  53}
  54
  55static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
  56{
  57        struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
  58        struct ceph_monmap *monmap = fsc->client->monc.monmap;
  59        struct ceph_statfs st;
  60        u64 fsid;
  61        int err;
  62
  63        dout("statfs\n");
  64        err = ceph_monc_do_statfs(&fsc->client->monc, &st);
  65        if (err < 0)
  66                return err;
  67
  68        /* fill in kstatfs */
  69        buf->f_type = CEPH_SUPER_MAGIC;  /* ?? */
  70
  71        /*
  72         * express utilization in terms of large blocks to avoid
  73         * overflow on 32-bit machines.
  74         *
  75         * NOTE: for the time being, we make bsize == frsize to humor
  76         * not-yet-ancient versions of glibc that are broken.
  77         * Someday, we will probably want to report a real block
  78         * size...  whatever that may mean for a network file system!
  79         */
  80        buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
  81        buf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
  82        buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
  83        buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
  84        buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
  85
  86        buf->f_files = le64_to_cpu(st.num_objects);
  87        buf->f_ffree = -1;
  88        buf->f_namelen = NAME_MAX;
  89
  90        /* leave fsid little-endian, regardless of host endianness */
  91        fsid = *(u64 *)(&monmap->fsid) ^ *((u64 *)&monmap->fsid + 1);
  92        buf->f_fsid.val[0] = fsid & 0xffffffff;
  93        buf->f_fsid.val[1] = fsid >> 32;
  94
  95        return 0;
  96}
  97
  98
  99static int ceph_sync_fs(struct super_block *sb, int wait)
 100{
 101        struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
 102
 103        if (!wait) {
 104                dout("sync_fs (non-blocking)\n");
 105                ceph_flush_dirty_caps(fsc->mdsc);
 106                dout("sync_fs (non-blocking) done\n");
 107                return 0;
 108        }
 109
 110        dout("sync_fs (blocking)\n");
 111        ceph_osdc_sync(&fsc->client->osdc);
 112        ceph_mdsc_sync(fsc->mdsc);
 113        dout("sync_fs (blocking) done\n");
 114        return 0;
 115}
 116
 117/*
 118 * mount options
 119 */
 120enum {
 121        Opt_wsize,
 122        Opt_rsize,
 123        Opt_rasize,
 124        Opt_caps_wanted_delay_min,
 125        Opt_caps_wanted_delay_max,
 126        Opt_cap_release_safety,
 127        Opt_readdir_max_entries,
 128        Opt_readdir_max_bytes,
 129        Opt_congestion_kb,
 130        Opt_last_int,
 131        /* int args above */
 132        Opt_snapdirname,
 133        Opt_last_string,
 134        /* string args above */
 135        Opt_dirstat,
 136        Opt_nodirstat,
 137        Opt_rbytes,
 138        Opt_norbytes,
 139        Opt_asyncreaddir,
 140        Opt_noasyncreaddir,
 141        Opt_dcache,
 142        Opt_nodcache,
 143        Opt_ino32,
 144        Opt_noino32,
 145};
 146
 147static match_table_t fsopt_tokens = {
 148        {Opt_wsize, "wsize=%d"},
 149        {Opt_rsize, "rsize=%d"},
 150        {Opt_rasize, "rasize=%d"},
 151        {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
 152        {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
 153        {Opt_cap_release_safety, "cap_release_safety=%d"},
 154        {Opt_readdir_max_entries, "readdir_max_entries=%d"},
 155        {Opt_readdir_max_bytes, "readdir_max_bytes=%d"},
 156        {Opt_congestion_kb, "write_congestion_kb=%d"},
 157        /* int args above */
 158        {Opt_snapdirname, "snapdirname=%s"},
 159        /* string args above */
 160        {Opt_dirstat, "dirstat"},
 161        {Opt_nodirstat, "nodirstat"},
 162        {Opt_rbytes, "rbytes"},
 163        {Opt_norbytes, "norbytes"},
 164        {Opt_asyncreaddir, "asyncreaddir"},
 165        {Opt_noasyncreaddir, "noasyncreaddir"},
 166        {Opt_dcache, "dcache"},
 167        {Opt_nodcache, "nodcache"},
 168        {Opt_ino32, "ino32"},
 169        {Opt_noino32, "noino32"},
 170        {-1, NULL}
 171};
 172
 173static int parse_fsopt_token(char *c, void *private)
 174{
 175        struct ceph_mount_options *fsopt = private;
 176        substring_t argstr[MAX_OPT_ARGS];
 177        int token, intval, ret;
 178
 179        token = match_token((char *)c, fsopt_tokens, argstr);
 180        if (token < 0)
 181                return -EINVAL;
 182
 183        if (token < Opt_last_int) {
 184                ret = match_int(&argstr[0], &intval);
 185                if (ret < 0) {
 186                        pr_err("bad mount option arg (not int) "
 187                               "at '%s'\n", c);
 188                        return ret;
 189                }
 190                dout("got int token %d val %d\n", token, intval);
 191        } else if (token > Opt_last_int && token < Opt_last_string) {
 192                dout("got string token %d val %s\n", token,
 193                     argstr[0].from);
 194        } else {
 195                dout("got token %d\n", token);
 196        }
 197
 198        switch (token) {
 199        case Opt_snapdirname:
 200                kfree(fsopt->snapdir_name);
 201                fsopt->snapdir_name = kstrndup(argstr[0].from,
 202                                               argstr[0].to-argstr[0].from,
 203                                               GFP_KERNEL);
 204                if (!fsopt->snapdir_name)
 205                        return -ENOMEM;
 206                break;
 207
 208                /* misc */
 209        case Opt_wsize:
 210                fsopt->wsize = intval;
 211                break;
 212        case Opt_rsize:
 213                fsopt->rsize = intval;
 214                break;
 215        case Opt_rasize:
 216                fsopt->rasize = intval;
 217                break;
 218        case Opt_caps_wanted_delay_min:
 219                fsopt->caps_wanted_delay_min = intval;
 220                break;
 221        case Opt_caps_wanted_delay_max:
 222                fsopt->caps_wanted_delay_max = intval;
 223                break;
 224        case Opt_readdir_max_entries:
 225                fsopt->max_readdir = intval;
 226                break;
 227        case Opt_readdir_max_bytes:
 228                fsopt->max_readdir_bytes = intval;
 229                break;
 230        case Opt_congestion_kb:
 231                fsopt->congestion_kb = intval;
 232                break;
 233        case Opt_dirstat:
 234                fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
 235                break;
 236        case Opt_nodirstat:
 237                fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
 238                break;
 239        case Opt_rbytes:
 240                fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
 241                break;
 242        case Opt_norbytes:
 243                fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
 244                break;
 245        case Opt_asyncreaddir:
 246                fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
 247                break;
 248        case Opt_noasyncreaddir:
 249                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
 250                break;
 251        case Opt_dcache:
 252                fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
 253                break;
 254        case Opt_nodcache:
 255                fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
 256                break;
 257        case Opt_ino32:
 258                fsopt->flags |= CEPH_MOUNT_OPT_INO32;
 259                break;
 260        case Opt_noino32:
 261                fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
 262                break;
 263        default:
 264                BUG_ON(token);
 265        }
 266        return 0;
 267}
 268
 269static void destroy_mount_options(struct ceph_mount_options *args)
 270{
 271        dout("destroy_mount_options %p\n", args);
 272        kfree(args->snapdir_name);
 273        kfree(args);
 274}
 275
 276static int strcmp_null(const char *s1, const char *s2)
 277{
 278        if (!s1 && !s2)
 279                return 0;
 280        if (s1 && !s2)
 281                return -1;
 282        if (!s1 && s2)
 283                return 1;
 284        return strcmp(s1, s2);
 285}
 286
 287static int compare_mount_options(struct ceph_mount_options *new_fsopt,
 288                                 struct ceph_options *new_opt,
 289                                 struct ceph_fs_client *fsc)
 290{
 291        struct ceph_mount_options *fsopt1 = new_fsopt;
 292        struct ceph_mount_options *fsopt2 = fsc->mount_options;
 293        int ofs = offsetof(struct ceph_mount_options, snapdir_name);
 294        int ret;
 295
 296        ret = memcmp(fsopt1, fsopt2, ofs);
 297        if (ret)
 298                return ret;
 299
 300        ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
 301        if (ret)
 302                return ret;
 303
 304        return ceph_compare_options(new_opt, fsc->client);
 305}
 306
 307static int parse_mount_options(struct ceph_mount_options **pfsopt,
 308                               struct ceph_options **popt,
 309                               int flags, char *options,
 310                               const char *dev_name,
 311                               const char **path)
 312{
 313        struct ceph_mount_options *fsopt;
 314        const char *dev_name_end;
 315        int err;
 316
 317        if (!dev_name || !*dev_name)
 318                return -EINVAL;
 319
 320        fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
 321        if (!fsopt)
 322                return -ENOMEM;
 323
 324        dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name);
 325
 326        fsopt->sb_flags = flags;
 327        fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
 328
 329        fsopt->rsize = CEPH_RSIZE_DEFAULT;
 330        fsopt->rasize = CEPH_RASIZE_DEFAULT;
 331        fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
 332        fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
 333        fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
 334        fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
 335        fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
 336        fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
 337        fsopt->congestion_kb = default_congestion_kb();
 338
 339        /*
 340         * Distinguish the server list from the path in "dev_name".
 341         * Internally we do not include the leading '/' in the path.
 342         *
 343         * "dev_name" will look like:
 344         *     <server_spec>[,<server_spec>...]:[<path>]
 345         * where
 346         *     <server_spec> is <ip>[:<port>]
 347         *     <path> is optional, but if present must begin with '/'
 348         */
 349        dev_name_end = strchr(dev_name, '/');
 350        if (dev_name_end) {
 351                /* skip over leading '/' for path */
 352                *path = dev_name_end + 1;
 353        } else {
 354                /* path is empty */
 355                dev_name_end = dev_name + strlen(dev_name);
 356                *path = dev_name_end;
 357        }
 358        err = -EINVAL;
 359        dev_name_end--;         /* back up to ':' separator */
 360        if (*dev_name_end != ':') {
 361                pr_err("device name is missing path (no : separator in %s)\n",
 362                                dev_name);
 363                goto out;
 364        }
 365        dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
 366        dout("server path '%s'\n", *path);
 367
 368        *popt = ceph_parse_options(options, dev_name, dev_name_end,
 369                                 parse_fsopt_token, (void *)fsopt);
 370        if (IS_ERR(*popt)) {
 371                err = PTR_ERR(*popt);
 372                goto out;
 373        }
 374
 375        /* success */
 376        *pfsopt = fsopt;
 377        return 0;
 378
 379out:
 380        destroy_mount_options(fsopt);
 381        return err;
 382}
 383
 384/**
 385 * ceph_show_options - Show mount options in /proc/mounts
 386 * @m: seq_file to write to
 387 * @root: root of that (sub)tree
 388 */
 389static int ceph_show_options(struct seq_file *m, struct dentry *root)
 390{
 391        struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb);
 392        struct ceph_mount_options *fsopt = fsc->mount_options;
 393        struct ceph_options *opt = fsc->client->options;
 394
 395        if (opt->flags & CEPH_OPT_FSID)
 396                seq_printf(m, ",fsid=%pU", &opt->fsid);
 397        if (opt->flags & CEPH_OPT_NOSHARE)
 398                seq_puts(m, ",noshare");
 399        if (opt->flags & CEPH_OPT_NOCRC)
 400                seq_puts(m, ",nocrc");
 401
 402        if (opt->name)
 403                seq_printf(m, ",name=%s", opt->name);
 404        if (opt->key)
 405                seq_puts(m, ",secret=<hidden>");
 406
 407        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
 408                seq_printf(m, ",mount_timeout=%d", opt->mount_timeout);
 409        if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
 410                seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl);
 411        if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
 412                seq_printf(m, ",osdkeepalivetimeout=%d",
 413                           opt->osd_keepalive_timeout);
 414
 415        if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
 416                seq_puts(m, ",dirstat");
 417        if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES) == 0)
 418                seq_puts(m, ",norbytes");
 419        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
 420                seq_puts(m, ",noasyncreaddir");
 421        if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE)
 422                seq_puts(m, ",dcache");
 423        else
 424                seq_puts(m, ",nodcache");
 425
 426        if (fsopt->wsize)
 427                seq_printf(m, ",wsize=%d", fsopt->wsize);
 428        if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
 429                seq_printf(m, ",rsize=%d", fsopt->rsize);
 430        if (fsopt->rasize != CEPH_RASIZE_DEFAULT)
 431                seq_printf(m, ",rasize=%d", fsopt->rasize);
 432        if (fsopt->congestion_kb != default_congestion_kb())
 433                seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb);
 434        if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
 435                seq_printf(m, ",caps_wanted_delay_min=%d",
 436                         fsopt->caps_wanted_delay_min);
 437        if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
 438                seq_printf(m, ",caps_wanted_delay_max=%d",
 439                           fsopt->caps_wanted_delay_max);
 440        if (fsopt->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT)
 441                seq_printf(m, ",cap_release_safety=%d",
 442                           fsopt->cap_release_safety);
 443        if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT)
 444                seq_printf(m, ",readdir_max_entries=%d", fsopt->max_readdir);
 445        if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
 446                seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
 447        if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
 448                seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name);
 449        return 0;
 450}
 451
 452/*
 453 * handle any mon messages the standard library doesn't understand.
 454 * return error if we don't either.
 455 */
 456static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
 457{
 458        struct ceph_fs_client *fsc = client->private;
 459        int type = le16_to_cpu(msg->hdr.type);
 460
 461        switch (type) {
 462        case CEPH_MSG_MDS_MAP:
 463                ceph_mdsc_handle_map(fsc->mdsc, msg);
 464                return 0;
 465
 466        default:
 467                return -1;
 468        }
 469}
 470
 471/*
 472 * create a new fs client
 473 */
 474static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
 475                                        struct ceph_options *opt)
 476{
 477        struct ceph_fs_client *fsc;
 478        const unsigned supported_features =
 479                CEPH_FEATURE_FLOCK |
 480                CEPH_FEATURE_DIRLAYOUTHASH;
 481        const unsigned required_features = 0;
 482        int err = -ENOMEM;
 483
 484        fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
 485        if (!fsc)
 486                return ERR_PTR(-ENOMEM);
 487
 488        fsc->client = ceph_create_client(opt, fsc, supported_features,
 489                                         required_features);
 490        if (IS_ERR(fsc->client)) {
 491                err = PTR_ERR(fsc->client);
 492                goto fail;
 493        }
 494        fsc->client->extra_mon_dispatch = extra_mon_dispatch;
 495        fsc->client->monc.want_mdsmap = 1;
 496
 497        fsc->mount_options = fsopt;
 498
 499        fsc->sb = NULL;
 500        fsc->mount_state = CEPH_MOUNT_MOUNTING;
 501
 502        atomic_long_set(&fsc->writeback_count, 0);
 503
 504        err = bdi_init(&fsc->backing_dev_info);
 505        if (err < 0)
 506                goto fail_client;
 507
 508        err = -ENOMEM;
 509        /*
 510         * The number of concurrent works can be high but they don't need
 511         * to be processed in parallel, limit concurrency.
 512         */
 513        fsc->wb_wq = alloc_workqueue("ceph-writeback", 0, 1);
 514        if (fsc->wb_wq == NULL)
 515                goto fail_bdi;
 516        fsc->pg_inv_wq = alloc_workqueue("ceph-pg-invalid", 0, 1);
 517        if (fsc->pg_inv_wq == NULL)
 518                goto fail_wb_wq;
 519        fsc->trunc_wq = alloc_workqueue("ceph-trunc", 0, 1);
 520        if (fsc->trunc_wq == NULL)
 521                goto fail_pg_inv_wq;
 522
 523        /* set up mempools */
 524        err = -ENOMEM;
 525        fsc->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
 526                              fsc->mount_options->wsize >> PAGE_CACHE_SHIFT);
 527        if (!fsc->wb_pagevec_pool)
 528                goto fail_trunc_wq;
 529
 530        /* caps */
 531        fsc->min_caps = fsopt->max_readdir;
 532
 533        return fsc;
 534
 535fail_trunc_wq:
 536        destroy_workqueue(fsc->trunc_wq);
 537fail_pg_inv_wq:
 538        destroy_workqueue(fsc->pg_inv_wq);
 539fail_wb_wq:
 540        destroy_workqueue(fsc->wb_wq);
 541fail_bdi:
 542        bdi_destroy(&fsc->backing_dev_info);
 543fail_client:
 544        ceph_destroy_client(fsc->client);
 545fail:
 546        kfree(fsc);
 547        return ERR_PTR(err);
 548}
 549
 550static void destroy_fs_client(struct ceph_fs_client *fsc)
 551{
 552        dout("destroy_fs_client %p\n", fsc);
 553
 554        destroy_workqueue(fsc->wb_wq);
 555        destroy_workqueue(fsc->pg_inv_wq);
 556        destroy_workqueue(fsc->trunc_wq);
 557
 558        bdi_destroy(&fsc->backing_dev_info);
 559
 560        mempool_destroy(fsc->wb_pagevec_pool);
 561
 562        destroy_mount_options(fsc->mount_options);
 563
 564        ceph_fs_debugfs_cleanup(fsc);
 565
 566        ceph_destroy_client(fsc->client);
 567
 568        kfree(fsc);
 569        dout("destroy_fs_client %p done\n", fsc);
 570}
 571
 572/*
 573 * caches
 574 */
 575struct kmem_cache *ceph_inode_cachep;
 576struct kmem_cache *ceph_cap_cachep;
 577struct kmem_cache *ceph_dentry_cachep;
 578struct kmem_cache *ceph_file_cachep;
 579
 580static void ceph_inode_init_once(void *foo)
 581{
 582        struct ceph_inode_info *ci = foo;
 583        inode_init_once(&ci->vfs_inode);
 584}
 585
 586static int __init init_caches(void)
 587{
 588        ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
 589                                      sizeof(struct ceph_inode_info),
 590                                      __alignof__(struct ceph_inode_info),
 591                                      (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
 592                                      ceph_inode_init_once);
 593        if (ceph_inode_cachep == NULL)
 594                return -ENOMEM;
 595
 596        ceph_cap_cachep = KMEM_CACHE(ceph_cap,
 597                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 598        if (ceph_cap_cachep == NULL)
 599                goto bad_cap;
 600
 601        ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
 602                                        SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 603        if (ceph_dentry_cachep == NULL)
 604                goto bad_dentry;
 605
 606        ceph_file_cachep = KMEM_CACHE(ceph_file_info,
 607                                      SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 608        if (ceph_file_cachep == NULL)
 609                goto bad_file;
 610
 611        return 0;
 612
 613bad_file:
 614        kmem_cache_destroy(ceph_dentry_cachep);
 615bad_dentry:
 616        kmem_cache_destroy(ceph_cap_cachep);
 617bad_cap:
 618        kmem_cache_destroy(ceph_inode_cachep);
 619        return -ENOMEM;
 620}
 621
 622static void destroy_caches(void)
 623{
 624        /*
 625         * Make sure all delayed rcu free inodes are flushed before we
 626         * destroy cache.
 627         */
 628        rcu_barrier();
 629        kmem_cache_destroy(ceph_inode_cachep);
 630        kmem_cache_destroy(ceph_cap_cachep);
 631        kmem_cache_destroy(ceph_dentry_cachep);
 632        kmem_cache_destroy(ceph_file_cachep);
 633}
 634
 635
 636/*
 637 * ceph_umount_begin - initiate forced umount.  Tear down down the
 638 * mount, skipping steps that may hang while waiting for server(s).
 639 */
 640static void ceph_umount_begin(struct super_block *sb)
 641{
 642        struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
 643
 644        dout("ceph_umount_begin - starting forced umount\n");
 645        if (!fsc)
 646                return;
 647        fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
 648        return;
 649}
 650
 651static const struct super_operations ceph_super_ops = {
 652        .alloc_inode    = ceph_alloc_inode,
 653        .destroy_inode  = ceph_destroy_inode,
 654        .write_inode    = ceph_write_inode,
 655        .sync_fs        = ceph_sync_fs,
 656        .put_super      = ceph_put_super,
 657        .show_options   = ceph_show_options,
 658        .statfs         = ceph_statfs,
 659        .umount_begin   = ceph_umount_begin,
 660};
 661
 662/*
 663 * Bootstrap mount by opening the root directory.  Note the mount
 664 * @started time from caller, and time out if this takes too long.
 665 */
 666static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
 667                                       const char *path,
 668                                       unsigned long started)
 669{
 670        struct ceph_mds_client *mdsc = fsc->mdsc;
 671        struct ceph_mds_request *req = NULL;
 672        int err;
 673        struct dentry *root;
 674
 675        /* open dir */
 676        dout("open_root_inode opening '%s'\n", path);
 677        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
 678        if (IS_ERR(req))
 679                return ERR_CAST(req);
 680        req->r_path1 = kstrdup(path, GFP_NOFS);
 681        req->r_ino1.ino = CEPH_INO_ROOT;
 682        req->r_ino1.snap = CEPH_NOSNAP;
 683        req->r_started = started;
 684        req->r_timeout = fsc->client->options->mount_timeout * HZ;
 685        req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
 686        req->r_num_caps = 2;
 687        err = ceph_mdsc_do_request(mdsc, NULL, req);
 688        if (err == 0) {
 689                struct inode *inode = req->r_target_inode;
 690                req->r_target_inode = NULL;
 691                dout("open_root_inode success\n");
 692                if (ceph_ino(inode) == CEPH_INO_ROOT &&
 693                    fsc->sb->s_root == NULL) {
 694                        root = d_make_root(inode);
 695                        if (!root) {
 696                                root = ERR_PTR(-ENOMEM);
 697                                goto out;
 698                        }
 699                } else {
 700                        root = d_obtain_alias(inode);
 701                }
 702                ceph_init_dentry(root);
 703                dout("open_root_inode success, root dentry is %p\n", root);
 704        } else {
 705                root = ERR_PTR(err);
 706        }
 707out:
 708        ceph_mdsc_put_request(req);
 709        return root;
 710}
 711
 712
 713
 714
 715/*
 716 * mount: join the ceph cluster, and open root directory.
 717 */
 718static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
 719                      const char *path)
 720{
 721        int err;
 722        unsigned long started = jiffies;  /* note the start time */
 723        struct dentry *root;
 724        int first = 0;   /* first vfsmount for this super_block */
 725
 726        dout("mount start\n");
 727        mutex_lock(&fsc->client->mount_mutex);
 728
 729        err = __ceph_open_session(fsc->client, started);
 730        if (err < 0)
 731                goto out;
 732
 733        dout("mount opening root\n");
 734        root = open_root_dentry(fsc, "", started);
 735        if (IS_ERR(root)) {
 736                err = PTR_ERR(root);
 737                goto out;
 738        }
 739        if (fsc->sb->s_root) {
 740                dput(root);
 741        } else {
 742                fsc->sb->s_root = root;
 743                first = 1;
 744
 745                err = ceph_fs_debugfs_init(fsc);
 746                if (err < 0)
 747                        goto fail;
 748        }
 749
 750        if (path[0] == 0) {
 751                dget(root);
 752        } else {
 753                dout("mount opening base mountpoint\n");
 754                root = open_root_dentry(fsc, path, started);
 755                if (IS_ERR(root)) {
 756                        err = PTR_ERR(root);
 757                        goto fail;
 758                }
 759        }
 760
 761        fsc->mount_state = CEPH_MOUNT_MOUNTED;
 762        dout("mount success\n");
 763        mutex_unlock(&fsc->client->mount_mutex);
 764        return root;
 765
 766out:
 767        mutex_unlock(&fsc->client->mount_mutex);
 768        return ERR_PTR(err);
 769
 770fail:
 771        if (first) {
 772                dput(fsc->sb->s_root);
 773                fsc->sb->s_root = NULL;
 774        }
 775        goto out;
 776}
 777
 778static int ceph_set_super(struct super_block *s, void *data)
 779{
 780        struct ceph_fs_client *fsc = data;
 781        int ret;
 782
 783        dout("set_super %p data %p\n", s, data);
 784
 785        s->s_flags = fsc->mount_options->sb_flags;
 786        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
 787
 788        s->s_fs_info = fsc;
 789        fsc->sb = s;
 790
 791        s->s_op = &ceph_super_ops;
 792        s->s_export_op = &ceph_export_ops;
 793
 794        s->s_time_gran = 1000;  /* 1000 ns == 1 us */
 795
 796        ret = set_anon_super(s, NULL);  /* what is that second arg for? */
 797        if (ret != 0)
 798                goto fail;
 799
 800        return ret;
 801
 802fail:
 803        s->s_fs_info = NULL;
 804        fsc->sb = NULL;
 805        return ret;
 806}
 807
 808/*
 809 * share superblock if same fs AND options
 810 */
 811static int ceph_compare_super(struct super_block *sb, void *data)
 812{
 813        struct ceph_fs_client *new = data;
 814        struct ceph_mount_options *fsopt = new->mount_options;
 815        struct ceph_options *opt = new->client->options;
 816        struct ceph_fs_client *other = ceph_sb_to_client(sb);
 817
 818        dout("ceph_compare_super %p\n", sb);
 819
 820        if (compare_mount_options(fsopt, opt, other)) {
 821                dout("monitor(s)/mount options don't match\n");
 822                return 0;
 823        }
 824        if ((opt->flags & CEPH_OPT_FSID) &&
 825            ceph_fsid_compare(&opt->fsid, &other->client->fsid)) {
 826                dout("fsid doesn't match\n");
 827                return 0;
 828        }
 829        if (fsopt->sb_flags != other->mount_options->sb_flags) {
 830                dout("flags differ\n");
 831                return 0;
 832        }
 833        return 1;
 834}
 835
 836/*
 837 * construct our own bdi so we can control readahead, etc.
 838 */
 839static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
 840
 841static int ceph_register_bdi(struct super_block *sb,
 842                             struct ceph_fs_client *fsc)
 843{
 844        int err;
 845
 846        /* set ra_pages based on rasize mount option? */
 847        if (fsc->mount_options->rasize >= PAGE_CACHE_SIZE)
 848                fsc->backing_dev_info.ra_pages =
 849                        (fsc->mount_options->rasize + PAGE_CACHE_SIZE - 1)
 850                        >> PAGE_SHIFT;
 851        else
 852                fsc->backing_dev_info.ra_pages =
 853                        default_backing_dev_info.ra_pages;
 854
 855        err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%ld",
 856                           atomic_long_inc_return(&bdi_seq));
 857        if (!err)
 858                sb->s_bdi = &fsc->backing_dev_info;
 859        return err;
 860}
 861
 862static struct dentry *ceph_mount(struct file_system_type *fs_type,
 863                       int flags, const char *dev_name, void *data)
 864{
 865        struct super_block *sb;
 866        struct ceph_fs_client *fsc;
 867        struct dentry *res;
 868        int err;
 869        int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
 870        const char *path = NULL;
 871        struct ceph_mount_options *fsopt = NULL;
 872        struct ceph_options *opt = NULL;
 873
 874        dout("ceph_mount\n");
 875        err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
 876        if (err < 0) {
 877                res = ERR_PTR(err);
 878                goto out_final;
 879        }
 880
 881        /* create client (which we may/may not use) */
 882        fsc = create_fs_client(fsopt, opt);
 883        if (IS_ERR(fsc)) {
 884                res = ERR_CAST(fsc);
 885                destroy_mount_options(fsopt);
 886                ceph_destroy_options(opt);
 887                goto out_final;
 888        }
 889
 890        err = ceph_mdsc_init(fsc);
 891        if (err < 0) {
 892                res = ERR_PTR(err);
 893                goto out;
 894        }
 895
 896        if (ceph_test_opt(fsc->client, NOSHARE))
 897                compare_super = NULL;
 898        sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
 899        if (IS_ERR(sb)) {
 900                res = ERR_CAST(sb);
 901                goto out;
 902        }
 903
 904        if (ceph_sb_to_client(sb) != fsc) {
 905                ceph_mdsc_destroy(fsc);
 906                destroy_fs_client(fsc);
 907                fsc = ceph_sb_to_client(sb);
 908                dout("get_sb got existing client %p\n", fsc);
 909        } else {
 910                dout("get_sb using new client %p\n", fsc);
 911                err = ceph_register_bdi(sb, fsc);
 912                if (err < 0) {
 913                        res = ERR_PTR(err);
 914                        goto out_splat;
 915                }
 916        }
 917
 918        res = ceph_real_mount(fsc, path);
 919        if (IS_ERR(res))
 920                goto out_splat;
 921        dout("root %p inode %p ino %llx.%llx\n", res,
 922             res->d_inode, ceph_vinop(res->d_inode));
 923        return res;
 924
 925out_splat:
 926        ceph_mdsc_close_sessions(fsc->mdsc);
 927        deactivate_locked_super(sb);
 928        goto out_final;
 929
 930out:
 931        ceph_mdsc_destroy(fsc);
 932        destroy_fs_client(fsc);
 933out_final:
 934        dout("ceph_mount fail %ld\n", PTR_ERR(res));
 935        return res;
 936}
 937
 938static void ceph_kill_sb(struct super_block *s)
 939{
 940        struct ceph_fs_client *fsc = ceph_sb_to_client(s);
 941        dout("kill_sb %p\n", s);
 942        ceph_mdsc_pre_umount(fsc->mdsc);
 943        kill_anon_super(s);    /* will call put_super after sb is r/o */
 944        ceph_mdsc_destroy(fsc);
 945        destroy_fs_client(fsc);
 946}
 947
 948static struct file_system_type ceph_fs_type = {
 949        .owner          = THIS_MODULE,
 950        .name           = "ceph",
 951        .mount          = ceph_mount,
 952        .kill_sb        = ceph_kill_sb,
 953        .fs_flags       = FS_RENAME_DOES_D_MOVE,
 954};
 955MODULE_ALIAS_FS("ceph");
 956
 957#define _STRINGIFY(x) #x
 958#define STRINGIFY(x) _STRINGIFY(x)
 959
 960static int __init init_ceph(void)
 961{
 962        int ret = init_caches();
 963        if (ret)
 964                goto out;
 965
 966        ceph_xattr_init();
 967        ret = register_filesystem(&ceph_fs_type);
 968        if (ret)
 969                goto out_icache;
 970
 971        pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
 972
 973        return 0;
 974
 975out_icache:
 976        ceph_xattr_exit();
 977        destroy_caches();
 978out:
 979        return ret;
 980}
 981
 982static void __exit exit_ceph(void)
 983{
 984        dout("exit_ceph\n");
 985        unregister_filesystem(&ceph_fs_type);
 986        ceph_xattr_exit();
 987        destroy_caches();
 988}
 989
 990module_init(init_ceph);
 991module_exit(exit_ceph);
 992
 993MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
 994MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
 995MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
 996MODULE_DESCRIPTION("Ceph filesystem for Linux");
 997MODULE_LICENSE("GPL");
 998
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.