ARM64: rockchip: cpufreq-dt: enable CPUFREQ_HAVE_GOVERNOR_PER_POLICY
[firefly-linux-kernel-4.4.55.git] / fs / ceph / super.c
index 7d377c9a5e35a6f05a9224495fb91574acd1d30f..f446afada328a45c2b70f648cbb48261e11e996c 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 
 #include <linux/ceph/ceph_features.h>
 #include <linux/ceph/decode.h>
@@ -39,22 +40,11 @@ static void ceph_put_super(struct super_block *s)
 
        dout("put_super\n");
        ceph_mdsc_close_sessions(fsc->mdsc);
-
-       /*
-        * ensure we release the bdi before put_anon_super releases
-        * the device name.
-        */
-       if (s->s_bdi == &fsc->backing_dev_info) {
-               bdi_unregister(&fsc->backing_dev_info);
-               s->s_bdi = NULL;
-       }
-
-       return;
 }
 
 static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
        struct ceph_monmap *monmap = fsc->client->monc.monmap;
        struct ceph_statfs st;
        u64 fsid;
@@ -142,6 +132,14 @@ enum {
        Opt_nodcache,
        Opt_ino32,
        Opt_noino32,
+       Opt_fscache,
+       Opt_nofscache,
+       Opt_poolperm,
+       Opt_nopoolperm,
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       Opt_acl,
+#endif
+       Opt_noacl,
 };
 
 static match_table_t fsopt_tokens = {
@@ -167,6 +165,14 @@ static match_table_t fsopt_tokens = {
        {Opt_nodcache, "nodcache"},
        {Opt_ino32, "ino32"},
        {Opt_noino32, "noino32"},
+       {Opt_fscache, "fsc"},
+       {Opt_nofscache, "nofsc"},
+       {Opt_poolperm, "poolperm"},
+       {Opt_nopoolperm, "nopoolperm"},
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       {Opt_acl, "acl"},
+#endif
+       {Opt_noacl, "noacl"},
        {-1, NULL}
 };
 
@@ -260,6 +266,27 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_noino32:
                fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
                break;
+       case Opt_fscache:
+               fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
+               break;
+       case Opt_nofscache:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
+               break;
+       case Opt_poolperm:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM;
+               printk ("pool perm");
+               break;
+       case Opt_nopoolperm:
+               fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM;
+               break;
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       case Opt_acl:
+               fsopt->sb_flags |= MS_POSIXACL;
+               break;
+#endif
+       case Opt_noacl:
+               fsopt->sb_flags &= ~MS_POSIXACL;
+               break;
        default:
                BUG_ON(token);
        }
@@ -329,6 +356,11 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
        fsopt->rsize = CEPH_RSIZE_DEFAULT;
        fsopt->rasize = CEPH_RASIZE_DEFAULT;
        fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+       if (!fsopt->snapdir_name) {
+               err = -ENOMEM;
+               goto out;
+       }
+
        fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
        fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
        fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
@@ -357,7 +389,7 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
        }
        err = -EINVAL;
        dev_name_end--;         /* back up to ':' separator */
-       if (*dev_name_end != ':') {
+       if (dev_name_end < dev_name || *dev_name_end != ':') {
                pr_err("device name is missing path (no : separator in %s)\n",
                                dev_name);
                goto out;
@@ -390,27 +422,20 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb);
        struct ceph_mount_options *fsopt = fsc->mount_options;
-       struct ceph_options *opt = fsc->client->options;
-
-       if (opt->flags & CEPH_OPT_FSID)
-               seq_printf(m, ",fsid=%pU", &opt->fsid);
-       if (opt->flags & CEPH_OPT_NOSHARE)
-               seq_puts(m, ",noshare");
-       if (opt->flags & CEPH_OPT_NOCRC)
-               seq_puts(m, ",nocrc");
-
-       if (opt->name)
-               seq_printf(m, ",name=%s", opt->name);
-       if (opt->key)
-               seq_puts(m, ",secret=<hidden>");
-
-       if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
-               seq_printf(m, ",mount_timeout=%d", opt->mount_timeout);
-       if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
-               seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl);
-       if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
-               seq_printf(m, ",osdkeepalivetimeout=%d",
-                          opt->osd_keepalive_timeout);
+       size_t pos;
+       int ret;
+
+       /* a comma between MNT/MS and client options */
+       seq_putc(m, ',');
+       pos = m->count;
+
+       ret = ceph_print_client_options(m, fsc->client);
+       if (ret)
+               return ret;
+
+       /* retract our comma if no client options */
+       if (m->count == pos)
+               m->count--;
 
        if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
                seq_puts(m, ",dirstat");
@@ -418,10 +443,19 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",norbytes");
        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
                seq_puts(m, ",noasyncreaddir");
-       if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE)
-               seq_puts(m, ",dcache");
-       else
+       if ((fsopt->flags & CEPH_MOUNT_OPT_DCACHE) == 0)
                seq_puts(m, ",nodcache");
+       if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE)
+               seq_puts(m, ",fsc");
+       if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM)
+               seq_puts(m, ",nopoolperm");
+
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       if (fsopt->sb_flags & MS_POSIXACL)
+               seq_puts(m, ",acl");
+       else
+               seq_puts(m, ",noacl");
+#endif
 
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
@@ -445,7 +479,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
        if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
                seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
        if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
-               seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name);
+               seq_show_option(m, "snapdirname", fsopt->snapdir_name);
+
        return 0;
 }
 
@@ -475,10 +510,11 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
                                        struct ceph_options *opt)
 {
        struct ceph_fs_client *fsc;
-       const unsigned supported_features =
+       const u64 supported_features =
                CEPH_FEATURE_FLOCK |
-               CEPH_FEATURE_DIRLAYOUTHASH;
-       const unsigned required_features = 0;
+               CEPH_FEATURE_DIRLAYOUTHASH |
+               CEPH_FEATURE_MDS_INLINE_DATA;
+       const u64 required_features = 0;
        int page_count;
        size_t size;
        int err = -ENOMEM;
@@ -530,11 +566,18 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
        if (!fsc->wb_pagevec_pool)
                goto fail_trunc_wq;
 
+       /* setup fscache */
+       if ((fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) &&
+           (ceph_fscache_register_fs(fsc) != 0))
+               goto fail_fscache;
+
        /* caps */
        fsc->min_caps = fsopt->max_readdir;
 
        return fsc;
 
+fail_fscache:
+       ceph_fscache_unregister_fs(fsc);
 fail_trunc_wq:
        destroy_workqueue(fsc->trunc_wq);
 fail_pg_inv_wq:
@@ -554,6 +597,8 @@ static void destroy_fs_client(struct ceph_fs_client *fsc)
 {
        dout("destroy_fs_client %p\n", fsc);
 
+       ceph_fscache_unregister_fs(fsc);
+
        destroy_workqueue(fsc->wb_wq);
        destroy_workqueue(fsc->pg_inv_wq);
        destroy_workqueue(fsc->trunc_wq);
@@ -577,6 +622,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc)
  */
 struct kmem_cache *ceph_inode_cachep;
 struct kmem_cache *ceph_cap_cachep;
+struct kmem_cache *ceph_cap_flush_cachep;
 struct kmem_cache *ceph_dentry_cachep;
 struct kmem_cache *ceph_file_cachep;
 
@@ -588,6 +634,8 @@ static void ceph_inode_init_once(void *foo)
 
 static int __init init_caches(void)
 {
+       int error = -ENOMEM;
+
        ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
                                      sizeof(struct ceph_inode_info),
                                      __alignof__(struct ceph_inode_info),
@@ -600,6 +648,10 @@ static int __init init_caches(void)
                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
        if (ceph_cap_cachep == NULL)
                goto bad_cap;
+       ceph_cap_flush_cachep = KMEM_CACHE(ceph_cap_flush,
+                                          SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_cap_flush_cachep == NULL)
+               goto bad_cap_flush;
 
        ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
                                        SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
@@ -611,15 +663,19 @@ static int __init init_caches(void)
        if (ceph_file_cachep == NULL)
                goto bad_file;
 
-       return 0;
+       if ((error = ceph_fscache_register()))
+               goto bad_file;
 
+       return 0;
 bad_file:
        kmem_cache_destroy(ceph_dentry_cachep);
 bad_dentry:
+       kmem_cache_destroy(ceph_cap_flush_cachep);
+bad_cap_flush:
        kmem_cache_destroy(ceph_cap_cachep);
 bad_cap:
        kmem_cache_destroy(ceph_inode_cachep);
-       return -ENOMEM;
+       return error;
 }
 
 static void destroy_caches(void)
@@ -629,10 +685,14 @@ static void destroy_caches(void)
         * destroy cache.
         */
        rcu_barrier();
+
        kmem_cache_destroy(ceph_inode_cachep);
        kmem_cache_destroy(ceph_cap_cachep);
+       kmem_cache_destroy(ceph_cap_flush_cachep);
        kmem_cache_destroy(ceph_dentry_cachep);
        kmem_cache_destroy(ceph_file_cachep);
+
+       ceph_fscache_unregister();
 }
 
 
@@ -648,6 +708,7 @@ static void ceph_umount_begin(struct super_block *sb)
        if (!fsc)
                return;
        fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
+       ceph_mdsc_force_umount(fsc->mdsc);
        return;
 }
 
@@ -655,6 +716,7 @@ static const struct super_operations ceph_super_ops = {
        .alloc_inode    = ceph_alloc_inode,
        .destroy_inode  = ceph_destroy_inode,
        .write_inode    = ceph_write_inode,
+       .drop_inode     = ceph_drop_inode,
        .sync_fs        = ceph_sync_fs,
        .put_super      = ceph_put_super,
        .show_options   = ceph_show_options,
@@ -681,10 +743,15 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
        if (IS_ERR(req))
                return ERR_CAST(req);
        req->r_path1 = kstrdup(path, GFP_NOFS);
+       if (!req->r_path1) {
+               root = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
        req->r_ino1.ino = CEPH_INO_ROOT;
        req->r_ino1.snap = CEPH_NOSNAP;
        req->r_started = started;
-       req->r_timeout = fsc->client->options->mount_timeout * HZ;
+       req->r_timeout = fsc->client->options->mount_timeout;
        req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
        req->r_num_caps = 2;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
@@ -700,7 +767,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                                goto out;
                        }
                } else {
-                       root = d_obtain_alias(inode);
+                       root = d_obtain_root(inode);
                }
                ceph_init_dentry(root);
                dout("open_root_inode success, root dentry is %p\n", root);
@@ -788,6 +855,7 @@ static int ceph_set_super(struct super_block *s, void *data)
        s->s_flags = fsc->mount_options->sb_flags;
        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
 
+       s->s_xattr = ceph_xattr_handlers;
        s->s_fs_info = fsc;
        fsc->sb = s;
 
@@ -853,7 +921,7 @@ static int ceph_register_bdi(struct super_block *sb,
                        >> PAGE_SHIFT;
        else
                fsc->backing_dev_info.ra_pages =
-                       default_backing_dev_info.ra_pages;
+                       VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE;
 
        err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%ld",
                           atomic_long_inc_return(&bdi_seq));
@@ -875,6 +943,10 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
        struct ceph_options *opt = NULL;
 
        dout("ceph_mount\n");
+
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       flags |= MS_POSIXACL;
+#endif
        err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
        if (err < 0) {
                res = ERR_PTR(err);
@@ -922,7 +994,7 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
        if (IS_ERR(res))
                goto out_splat;
        dout("root %p inode %p ino %llx.%llx\n", res,
-            res->d_inode, ceph_vinop(res->d_inode));
+            d_inode(res), ceph_vinop(d_inode(res)));
        return res;
 
 out_splat:
@@ -941,11 +1013,16 @@ out_final:
 static void ceph_kill_sb(struct super_block *s)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(s);
+       dev_t dev = s->s_dev;
+
        dout("kill_sb %p\n", s);
+
        ceph_mdsc_pre_umount(fsc->mdsc);
-       kill_anon_super(s);    /* will call put_super after sb is r/o */
+       generic_shutdown_super(s);
        ceph_mdsc_destroy(fsc);
+
        destroy_fs_client(fsc);
+       free_anon_bdev(dev);
 }
 
 static struct file_system_type ceph_fs_type = {
@@ -957,25 +1034,28 @@ static struct file_system_type ceph_fs_type = {
 };
 MODULE_ALIAS_FS("ceph");
 
-#define _STRINGIFY(x) #x
-#define STRINGIFY(x) _STRINGIFY(x)
-
 static int __init init_ceph(void)
 {
        int ret = init_caches();
        if (ret)
                goto out;
 
+       ceph_flock_init();
        ceph_xattr_init();
+       ret = ceph_snap_init();
+       if (ret)
+               goto out_xattr;
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
-               goto out_icache;
+               goto out_snap;
 
        pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
 
        return 0;
 
-out_icache:
+out_snap:
+       ceph_snap_exit();
+out_xattr:
        ceph_xattr_exit();
        destroy_caches();
 out:
@@ -986,6 +1066,7 @@ static void __exit exit_ceph(void)
 {
        dout("exit_ceph\n");
        unregister_filesystem(&ceph_fs_type);
+       ceph_snap_exit();
        ceph_xattr_exit();
        destroy_caches();
 }