GFS2: Fix error path ref counting for root inode
[safe/jmp/linux-2.6] / fs / gfs2 / ops_fstype.c
index b117fcf..e502b37 100644 (file)
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
 #include "bmap.h"
-#include "daemon.h"
 #include "glock.h"
 #include "glops.h"
 #include "inode.h"
-#include "mount.h"
-#include "ops_fstype.h"
-#include "ops_dentry.h"
-#include "ops_super.h"
 #include "recovery.h"
 #include "rgrp.h"
 #include "super.h"
 #include "sys.h"
 #include "util.h"
 #include "log.h"
+#include "quota.h"
+#include "dir.h"
 
 #define DO 0
 #define UNDO 1
@@ -58,17 +54,14 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
 {
        spin_lock_init(&gt->gt_spin);
 
-       gt->gt_demote_secs = 300;
        gt->gt_incore_log_blocks = 1024;
        gt->gt_log_flush_secs = 60;
        gt->gt_recoverd_secs = 60;
        gt->gt_logd_secs = 1;
-       gt->gt_quotad_secs = 5;
        gt->gt_quota_simul_sync = 64;
        gt->gt_quota_warn_period = 10;
        gt->gt_quota_scale_num = 1;
        gt->gt_quota_scale_den = 1;
-       gt->gt_quota_cache_secs = 300;
        gt->gt_quota_quantum = 60;
        gt->gt_new_files_jdata = 0;
        gt->gt_max_readahead = 1 << 18;
@@ -91,10 +84,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        gfs2_tune_init(&sdp->sd_tune);
 
-       INIT_LIST_HEAD(&sdp->sd_reclaim_list);
-       spin_lock_init(&sdp->sd_reclaim_lock);
-       init_waitqueue_head(&sdp->sd_reclaim_wq);
-
        mutex_init(&sdp->sd_inum_mutex);
        spin_lock_init(&sdp->sd_statfs_spin);
 
@@ -108,8 +97,10 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
        mutex_init(&sdp->sd_jindex_mutex);
 
        INIT_LIST_HEAD(&sdp->sd_quota_list);
-       spin_lock_init(&sdp->sd_quota_spin);
        mutex_init(&sdp->sd_quota_mutex);
+       init_waitqueue_head(&sdp->sd_quota_wait);
+       INIT_LIST_HEAD(&sdp->sd_trunc_list);
+       spin_lock_init(&sdp->sd_trunc_lock);
 
        spin_lock_init(&sdp->sd_log_lock);
 
@@ -443,24 +434,11 @@ out:
 static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
                        int undo)
 {
-       struct task_struct *p;
        int error = 0;
 
        if (undo)
                goto fail_trans;
 
-       for (sdp->sd_glockd_num = 0;
-            sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
-            sdp->sd_glockd_num++) {
-               p = kthread_run(gfs2_glockd, sdp, "gfs2_glockd");
-               error = IS_ERR(p);
-               if (error) {
-                       fs_err(sdp, "can't start glockd thread: %d\n", error);
-                       goto fail;
-               }
-               sdp->sd_glockd_process[sdp->sd_glockd_num] = p;
-       }
-
        error = gfs2_glock_nq_num(sdp,
                                  GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
                                  LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
@@ -493,7 +471,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
                fs_err(sdp, "can't create transaction glock: %d\n", error);
                goto fail_rename;
        }
-       set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags);
 
        return 0;
 
@@ -506,9 +483,6 @@ fail_live:
 fail_mount:
        gfs2_glock_dq_uninit(mount_gh);
 fail:
-       while (sdp->sd_glockd_num--)
-               kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
-
        return error;
 }
 
@@ -620,7 +594,7 @@ static int map_journal_extents(struct gfs2_sbd *sdp)
 
        prev_db = 0;
 
-       for (lb = 0; lb < ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; lb++) {
+       for (lb = 0; lb < ip->i_disksize >> sdp->sd_sb.sb_bsize_shift; lb++) {
                bh.b_state = 0;
                bh.b_blocknr = 0;
                bh.b_size = 1 << ip->i_inode.i_blkbits;
@@ -652,13 +626,79 @@ static int map_journal_extents(struct gfs2_sbd *sdp)
        return rc;
 }
 
-static void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
+static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
 {
-       if (!sdp->sd_lockstruct.ls_ops->lm_others_may_mount)
-               return;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
-                                       sdp->sd_lockstruct.ls_lockspace);
+       char *message = "FIRSTMOUNT=Done";
+       char *envp[] = { message, NULL };
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       ls->ls_first_done = 1;
+       kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
+}
+
+/**
+ * gfs2_jindex_hold - Grab a lock on the jindex
+ * @sdp: The GFS2 superblock
+ * @ji_gh: the holder for the jindex glock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
+{
+       struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex);
+       struct qstr name;
+       char buf[20];
+       struct gfs2_jdesc *jd;
+       int error;
+
+       name.name = buf;
+
+       mutex_lock(&sdp->sd_jindex_mutex);
+
+       for (;;) {
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
+               if (error)
+                       break;
+
+               name.len = sprintf(buf, "journal%u", sdp->sd_journals);
+               name.hash = gfs2_disk_hash(name.name, name.len);
+
+               error = gfs2_dir_check(sdp->sd_jindex, &name, NULL);
+               if (error == -ENOENT) {
+                       error = 0;
+                       break;
+               }
+
+               gfs2_glock_dq_uninit(ji_gh);
+
+               if (error)
+                       break;
+
+               error = -ENOMEM;
+               jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL);
+               if (!jd)
+                       break;
+
+               INIT_LIST_HEAD(&jd->extent_list);
+               jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
+               if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
+                       if (!jd->jd_inode)
+                               error = -ENOENT;
+                       else
+                               error = PTR_ERR(jd->jd_inode);
+                       kfree(jd);
+                       break;
+               }
+
+               spin_lock(&sdp->sd_jindex_spin);
+               jd->jd_jid = sdp->sd_journals++;
+               list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
+               spin_unlock(&sdp->sd_jindex_spin);
+       }
+
+       mutex_unlock(&sdp->sd_jindex_mutex);
+
+       return error;
 }
 
 static int init_journal(struct gfs2_sbd *sdp, int undo)
@@ -681,7 +721,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                return PTR_ERR(sdp->sd_jindex);
        }
        ip = GFS2_I(sdp->sd_jindex);
-       set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
 
        /* Load in the journal index special file */
 
@@ -753,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                        }
                }
 
-               gfs2_lm_others_may_mount(sdp);
+               gfs2_others_may_mount(sdp);
        } else if (!sdp->sd_args.ar_spectator) {
                error = gfs2_recover_journal(sdp->sd_jdesc);
                if (error) {
@@ -832,7 +871,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
                goto fail_statfs;
        }
        ip = GFS2_I(sdp->sd_rindex);
-       set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
        sdp->sd_rindex_uptodate = 0;
 
        /* Read in the quota inode */
@@ -963,7 +1001,6 @@ static int init_threads(struct gfs2_sbd *sdp, int undo)
                goto fail_quotad;
 
        sdp->sd_log_flush_time = jiffies;
-       sdp->sd_jindex_refresh_time = jiffies;
 
        p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
        error = IS_ERR(p);
@@ -973,9 +1010,6 @@ static int init_threads(struct gfs2_sbd *sdp, int undo)
        }
        sdp->sd_logd_process = p;
 
-       sdp->sd_statfs_sync_time = jiffies;
-       sdp->sd_quota_sync_time = jiffies;
-
        p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
        error = IS_ERR(p);
        if (error) {
@@ -994,6 +1028,17 @@ fail:
        return error;
 }
 
+static const match_table_t nolock_tokens = {
+       { Opt_jid, "jid=%d\n", },
+       { Opt_err, NULL },
+};
+
+static const struct lm_lockops nolock_ops = {
+       .lm_proto_name = "lock_nolock",
+       .lm_put_lock = kmem_cache_free,
+       .lm_tokens = &nolock_tokens,
+};
+
 /**
  * gfs2_lm_mount - mount a locking protocol
  * @sdp: the filesystem
@@ -1005,31 +1050,73 @@ fail:
 
 static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
 {
-       char *proto = sdp->sd_proto_name;
-       char *table = sdp->sd_table_name;
-       int flags = LM_MFLAG_CONV_NODROP;
-       int error;
+       const struct lm_lockops *lm;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       struct gfs2_args *args = &sdp->sd_args;
+       const char *proto = sdp->sd_proto_name;
+       const char *table = sdp->sd_table_name;
+       const char *fsname;
+       char *o, *options;
+       int ret;
 
-       if (sdp->sd_args.ar_spectator)
-               flags |= LM_MFLAG_SPECTATOR;
+       if (!strcmp("lock_nolock", proto)) {
+               lm = &nolock_ops;
+               sdp->sd_args.ar_localflocks = 1;
+               sdp->sd_args.ar_localcaching = 1;
+#ifdef CONFIG_GFS2_FS_LOCKING_DLM
+       } else if (!strcmp("lock_dlm", proto)) {
+               lm = &gfs2_dlm_ops;
+#endif
+       } else {
+               printk(KERN_INFO "GFS2: can't find protocol %s\n", proto);
+               return -ENOENT;
+       }
 
        fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
 
-       error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
-                                    gfs2_glock_cb, sdp,
-                                    GFS2_MIN_LVB_SIZE, flags,
-                                    &sdp->sd_lockstruct, &sdp->sd_kobj);
-       if (error) {
-               fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
-                       proto, table, sdp->sd_args.ar_hostdata);
-               goto out;
-       }
+       ls->ls_ops = lm;
+       ls->ls_first = 1;
+       ls->ls_id = 0;
 
-       if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
-           gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
-                                 GFS2_MIN_LVB_SIZE)) {
-               gfs2_unmount_lockproto(&sdp->sd_lockstruct);
-               goto out;
+       for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) {
+               substring_t tmp[MAX_OPT_ARGS];
+               int token, option;
+
+               if (!o || !*o)
+                       continue;
+
+               token = match_token(o, *lm->lm_tokens, tmp);
+               switch (token) {
+               case Opt_jid:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || option < 0) 
+                               goto hostdata_error;
+                       ls->ls_jid = option;
+                       break;
+               case Opt_id:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret)
+                               goto hostdata_error;
+                       ls->ls_id = option;
+                       break;
+               case Opt_first:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || (option != 0 && option != 1))
+                               goto hostdata_error;
+                       ls->ls_first = option;
+                       break;
+               case Opt_nodir:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || (option != 0 && option != 1))
+                               goto hostdata_error;
+                       ls->ls_nodir = option;
+                       break;
+               case Opt_err:
+               default:
+hostdata_error:
+                       fs_info(sdp, "unknown hostdata (%s)\n", o);
+                       return -EINVAL;
+               }
        }
 
        if (sdp->sd_args.ar_spectator)
@@ -1038,22 +1125,25 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
                snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
                         sdp->sd_lockstruct.ls_jid);
 
-       fs_info(sdp, "Joined cluster. Now mounting FS...\n");
-
-       if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
-           !sdp->sd_args.ar_ignore_local_fs) {
-               sdp->sd_args.ar_localflocks = 1;
-               sdp->sd_args.ar_localcaching = 1;
+       fsname = strchr(table, ':');
+       if (fsname)
+               fsname++;
+       if (lm->lm_mount == NULL) {
+               fs_info(sdp, "Now mounting FS...\n");
+               return 0;
        }
-
-out:
-       return error;
+       ret = lm->lm_mount(sdp, fsname);
+       if (ret == 0)
+               fs_info(sdp, "Joined cluster. Now mounting FS...\n");
+       return ret;
 }
 
 void gfs2_lm_unmount(struct gfs2_sbd *sdp)
 {
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+       const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
+       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) &&
+           lm->lm_unmount)
+               lm->lm_unmount(sdp);
 }
 
 /**
@@ -1077,12 +1167,20 @@ static int fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        }
 
-       error = gfs2_mount_args(sdp, (char *)data, 0);
+       sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
+       sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
+
+       error = gfs2_mount_args(sdp, &sdp->sd_args, data);
        if (error) {
                printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
                goto fail;
        }
 
+       if (sdp->sd_args.ar_spectator)
+                sb->s_flags |= MS_RDONLY;
+       if (sdp->sd_args.ar_posix_acl)
+               sb->s_flags |= MS_POSIXACL;
+
        sb->s_magic = GFS2_MAGIC;
        sb->s_op = &gfs2_super_ops;
        sb->s_export_op = &gfs2_export_ops;
@@ -1160,6 +1258,8 @@ fail_sb:
                dput(sdp->sd_root_dir);
        if (sdp->sd_master_dir)
                dput(sdp->sd_master_dir);
+       if (sb->s_root)
+               dput(sb->s_root);
        sb->s_root = NULL;
 fail_locking:
        init_locking(sdp, &mount_gh, UNDO);
@@ -1224,17 +1324,21 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
 static void gfs2_kill_sb(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       if (sdp) {
-               gfs2_meta_syncfs(sdp);
-               dput(sdp->sd_root_dir);
-               dput(sdp->sd_master_dir);
-               sdp->sd_root_dir = NULL;
-               sdp->sd_master_dir = NULL;
+
+       if (sdp == NULL) {
+               kill_block_super(sb);
+               return;
        }
+
+       gfs2_meta_syncfs(sdp);
+       dput(sdp->sd_root_dir);
+       dput(sdp->sd_master_dir);
+       sdp->sd_root_dir = NULL;
+       sdp->sd_master_dir = NULL;
        shrink_dcache_sb(sb);
        kill_block_super(sb);
-       if (sdp)
-               gfs2_delete_debugfs_file(sdp);
+       gfs2_delete_debugfs_file(sdp);
+       kfree(sdp);
 }
 
 struct file_system_type gfs2_fs_type = {