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