2006-01-16 17:50:04 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
2008-01-31 17:31:39 +01:00
|
|
|
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
2006-01-16 17:50:04 +01:00
|
|
|
*
|
|
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
2006-09-01 17:05:15 +02:00
|
|
|
* of the GNU General Public License version 2.
|
2006-01-16 17:50:04 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/completion.h>
|
|
|
|
#include <linux/buffer_head.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/kthread.h>
|
2011-05-26 22:00:52 +02:00
|
|
|
#include <linux/export.h>
|
2006-08-25 18:13:37 +02:00
|
|
|
#include <linux/namei.h>
|
|
|
|
#include <linux/mount.h>
|
2006-02-27 23:23:27 +01:00
|
|
|
#include <linux/gfs2_ondisk.h>
|
2009-09-15 10:59:02 +02:00
|
|
|
#include <linux/quotaops.h>
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
#include "gfs2.h"
|
2006-02-27 23:23:27 +01:00
|
|
|
#include "incore.h"
|
2007-12-12 01:49:21 +01:00
|
|
|
#include "bmap.h"
|
2006-01-16 17:50:04 +01:00
|
|
|
#include "glock.h"
|
|
|
|
#include "glops.h"
|
|
|
|
#include "inode.h"
|
|
|
|
#include "recovery.h"
|
|
|
|
#include "rgrp.h"
|
|
|
|
#include "super.h"
|
|
|
|
#include "sys.h"
|
2006-02-27 23:23:27 +01:00
|
|
|
#include "util.h"
|
2007-08-16 17:03:57 +02:00
|
|
|
#include "log.h"
|
2008-11-19 11:08:22 +01:00
|
|
|
#include "quota.h"
|
2008-11-26 13:49:26 +01:00
|
|
|
#include "dir.h"
|
2009-06-12 09:49:20 +02:00
|
|
|
#include "trace_gfs2.h"
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
#define DO 0
|
|
|
|
#define UNDO 1
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
/**
|
|
|
|
* gfs2_tune_init - Fill a gfs2_tune structure with default values
|
|
|
|
* @gt: tune
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void gfs2_tune_init(struct gfs2_tune *gt)
|
|
|
|
{
|
|
|
|
spin_lock_init(>->gt_spin);
|
|
|
|
|
|
|
|
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_new_files_jdata = 0;
|
|
|
|
gt->gt_max_readahead = 1 << 18;
|
|
|
|
gt->gt_complain_secs = 10;
|
|
|
|
}
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
|
|
|
{
|
|
|
|
struct gfs2_sbd *sdp;
|
|
|
|
|
2006-09-07 20:40:21 +02:00
|
|
|
sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!sdp)
|
|
|
|
return NULL;
|
|
|
|
|
2006-02-27 23:23:27 +01:00
|
|
|
sb->s_fs_info = sdp;
|
2006-01-16 17:50:04 +01:00
|
|
|
sdp->sd_vfs = sb;
|
GFS2: glock statistics gathering
The stats are divided into two sets: those relating to the
super block and those relating to an individual glock. The
super block stats are done on a per cpu basis in order to
try and reduce the overhead of gathering them. They are also
further divided by glock type.
In the case of both the super block and glock statistics,
the same information is gathered in each case. The super
block statistics are used to provide default values for
most of the glock statistics, so that newly created glocks
should have, as far as possible, a sensible starting point.
The statistics are divided into three pairs of mean and
variance, plus two counters. The mean/variance pairs are
smoothed exponential estimates and the algorithm used is
one which will be very familiar to those used to calculation
of round trip times in network code.
The three pairs of mean/variance measure the following
things:
1. DLM lock time (non-blocking requests)
2. DLM lock time (blocking requests)
3. Inter-request time (again to the DLM)
A non-blocking request is one which will complete right
away, whatever the state of the DLM lock in question. That
currently means any requests when (a) the current state of
the lock is exclusive (b) the requested state is either null
or unlocked or (c) the "try lock" flag is set. A blocking
request covers all the other lock requests.
There are two counters. The first is there primarily to show
how many lock requests have been made, and thus how much data
has gone into the mean/variance calculations. The other counter
is counting queueing of holders at the top layer of the glock
code. Hopefully that number will be a lot larger than the number
of dlm lock requests issued.
So why gather these statistics? There are several reasons
we'd like to get a better idea of these timings:
1. To be able to better set the glock "min hold time"
2. To spot performance issues more easily
3. To improve the algorithm for selecting resource groups for
allocation (to base it on lock wait time, rather than blindly
using a "try lock")
Due to the smoothing action of the updates, a step change in
some input quantity being sampled will only fully be taken
into account after 8 samples (or 4 for the variance) and this
needs to be carefully considered when interpreting the
results.
Knowing both the time it takes a lock request to complete and
the average time between lock requests for a glock means we
can compute the total percentage of the time for which the
node is able to use a glock vs. time that the rest of the
cluster has its share. That will be very useful when setting
the lock min hold time.
The other point to remember is that all times are in
nanoseconds. Great care has been taken to ensure that we
measure exactly the quantities that we want, as accurately
as possible. There are always inaccuracies in any
measuring system, but I hope this is as accurate as we
can reasonably make it.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2012-01-20 11:38:36 +01:00
|
|
|
sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
|
|
|
|
if (!sdp->sd_lkstats) {
|
|
|
|
kfree(sdp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-14 11:01:30 +02:00
|
|
|
set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_tune_init(&sdp->sd_tune);
|
|
|
|
|
2010-01-25 12:20:19 +01:00
|
|
|
init_waitqueue_head(&sdp->sd_glock_wait);
|
|
|
|
atomic_set(&sdp->sd_glock_disposal, 0);
|
2011-07-11 09:53:30 +02:00
|
|
|
init_completion(&sdp->sd_locking_init);
|
2006-01-16 17:50:04 +01:00
|
|
|
spin_lock_init(&sdp->sd_statfs_spin);
|
|
|
|
|
|
|
|
spin_lock_init(&sdp->sd_rindex_spin);
|
GFS2: Use rbtree for resource groups and clean up bitmap buffer ref count scheme
Here is an update of Bob's original rbtree patch which, in addition, also
resolves the rather strange ref counting that was being done relating to
the bitmap blocks.
Originally we had a dual system for journaling resource groups. The metadata
blocks were journaled and also the rgrp itself was added to a list. The reason
for adding the rgrp to the list in the journal was so that the "repolish
clones" code could be run to update the free space, and potentially send any
discard requests when the log was flushed. This was done by comparing the
"cloned" bitmap with what had been written back on disk during the transaction
commit.
Due to this, there was a requirement to hang on to the rgrps' bitmap buffers
until the journal had been flushed. For that reason, there was a rather
complicated set up in the ->go_lock ->go_unlock functions for rgrps involving
both a mutex and a spinlock (the ->sd_rindex_spin) to maintain a reference
count on the buffers.
However, the journal maintains a reference count on the buffers anyway, since
they are being journaled as metadata buffers. So by moving the code which deals
with the post-journal accounting for bitmap blocks to the metadata journaling
code, we can entirely dispense with the rather strange buffer ref counting
scheme and also the requirement to journal the rgrps.
The net result of all this is that the ->sd_rindex_spin is left to do exactly
one job, and that is to look after the rbtree or rgrps.
This patch is designed to be a stepping stone towards using RCU for the rbtree
of resource groups, however the reduction in the number of uses of the
->sd_rindex_spin is likely to have benefits for multi-threaded workloads,
anyway.
The patch retains ->go_lock and ->go_unlock for rgrps, however these maybe also
be removed in future in favour of calling the functions directly where required
in the code. That will allow locking of resource groups without needing to
actually read them in - something that could be useful in speeding up statfs.
In the mean time though it is valid to dereference ->bi_bh only when the rgrp
is locked. This is basically the same rule as before, modulo the references not
being valid until the following journal flush.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Cc: Benjamin Marzinski <bmarzins@redhat.com>
2011-08-31 10:53:19 +02:00
|
|
|
sdp->sd_rindex_tree.rb_node = NULL;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_jindex_list);
|
|
|
|
spin_lock_init(&sdp->sd_jindex_spin);
|
2006-02-21 13:51:39 +01:00
|
|
|
mutex_init(&sdp->sd_jindex_mutex);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_quota_list);
|
2006-02-21 13:51:39 +01:00
|
|
|
mutex_init(&sdp->sd_quota_mutex);
|
2008-11-17 15:25:37 +01:00
|
|
|
init_waitqueue_head(&sdp->sd_quota_wait);
|
2008-11-18 14:38:48 +01:00
|
|
|
INIT_LIST_HEAD(&sdp->sd_trunc_list);
|
|
|
|
spin_lock_init(&sdp->sd_trunc_lock);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
spin_lock_init(&sdp->sd_log_lock);
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
atomic_set(&sdp->sd_log_pinned, 0);
|
2006-01-16 17:50:04 +01:00
|
|
|
INIT_LIST_HEAD(&sdp->sd_log_le_buf);
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_log_le_rg);
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
|
2007-09-02 11:48:13 +02:00
|
|
|
INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
init_waitqueue_head(&sdp->sd_log_waitq);
|
|
|
|
init_waitqueue_head(&sdp->sd_logd_waitq);
|
2011-03-11 12:52:25 +01:00
|
|
|
spin_lock_init(&sdp->sd_ail_lock);
|
2006-01-16 17:50:04 +01:00
|
|
|
INIT_LIST_HEAD(&sdp->sd_ail1_list);
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_ail2_list);
|
|
|
|
|
2006-03-29 16:12:12 +02:00
|
|
|
init_rwsem(&sdp->sd_log_flush_lock);
|
2007-09-17 11:59:52 +02:00
|
|
|
atomic_set(&sdp->sd_log_in_flight, 0);
|
|
|
|
init_waitqueue_head(&sdp->sd_log_flush_wait);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&sdp->sd_revoke_list);
|
|
|
|
|
2006-02-21 13:51:39 +01:00
|
|
|
mutex_init(&sdp->sd_freeze_lock);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
return sdp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
/**
|
|
|
|
* gfs2_check_sb - Check superblock
|
|
|
|
* @sdp: the filesystem
|
|
|
|
* @sb: The superblock
|
|
|
|
* @silent: Don't print a message if the check fails
|
|
|
|
*
|
|
|
|
* Checks the version code of the FS is one that we understand how to
|
|
|
|
* read and that the sizes of the various on-disk structures have not
|
|
|
|
* changed.
|
|
|
|
*/
|
|
|
|
|
2011-05-10 16:01:59 +02:00
|
|
|
static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent)
|
2008-08-08 14:45:13 +02:00
|
|
|
{
|
2011-05-10 16:01:59 +02:00
|
|
|
struct gfs2_sb_host *sb = &sdp->sd_sb;
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
if (sb->sb_magic != GFS2_MAGIC ||
|
|
|
|
sb->sb_type != GFS2_METATYPE_SB) {
|
|
|
|
if (!silent)
|
|
|
|
printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If format numbers match exactly, we're done. */
|
|
|
|
|
|
|
|
if (sb->sb_fs_format == GFS2_FORMAT_FS &&
|
|
|
|
sb->sb_multihost_format == GFS2_FORMAT_MULTI)
|
|
|
|
return 0;
|
|
|
|
|
2010-09-24 10:55:07 +02:00
|
|
|
fs_warn(sdp, "Unknown on-disk format, unable to mount\n");
|
2008-08-08 14:45:13 +02:00
|
|
|
|
2010-09-24 10:55:07 +02:00
|
|
|
return -EINVAL;
|
2008-08-08 14:45:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void end_bio_io_page(struct bio *bio, int error)
|
|
|
|
{
|
|
|
|
struct page *page = bio->bi_private;
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
else
|
|
|
|
printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
|
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
|
2011-05-10 16:01:59 +02:00
|
|
|
static void gfs2_sb_in(struct gfs2_sbd *sdp, const void *buf)
|
2008-08-08 14:45:13 +02:00
|
|
|
{
|
2011-05-10 16:01:59 +02:00
|
|
|
struct gfs2_sb_host *sb = &sdp->sd_sb;
|
|
|
|
struct super_block *s = sdp->sd_vfs;
|
2008-08-08 14:45:13 +02:00
|
|
|
const struct gfs2_sb *str = buf;
|
|
|
|
|
|
|
|
sb->sb_magic = be32_to_cpu(str->sb_header.mh_magic);
|
|
|
|
sb->sb_type = be32_to_cpu(str->sb_header.mh_type);
|
|
|
|
sb->sb_format = be32_to_cpu(str->sb_header.mh_format);
|
|
|
|
sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
|
|
|
|
sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
|
|
|
|
sb->sb_bsize = be32_to_cpu(str->sb_bsize);
|
|
|
|
sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
|
|
|
|
sb->sb_master_dir.no_addr = be64_to_cpu(str->sb_master_dir.no_addr);
|
|
|
|
sb->sb_master_dir.no_formal_ino = be64_to_cpu(str->sb_master_dir.no_formal_ino);
|
|
|
|
sb->sb_root_dir.no_addr = be64_to_cpu(str->sb_root_dir.no_addr);
|
|
|
|
sb->sb_root_dir.no_formal_ino = be64_to_cpu(str->sb_root_dir.no_formal_ino);
|
|
|
|
|
|
|
|
memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
|
|
|
|
memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
|
2011-05-10 16:01:59 +02:00
|
|
|
memcpy(s->s_uuid, str->sb_uuid, 16);
|
2008-08-08 14:45:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_read_super - Read the gfs2 super block from disk
|
|
|
|
* @sdp: The GFS2 super block
|
|
|
|
* @sector: The location of the super block
|
|
|
|
* @error: The error code to return
|
|
|
|
*
|
|
|
|
* This uses the bio functions to read the super block from disk
|
|
|
|
* because we want to be 100% sure that we never read cached data.
|
|
|
|
* A super block is read twice only during each GFS2 mount and is
|
|
|
|
* never written to by the filesystem. The first time its read no
|
|
|
|
* locks are held, and the only details which are looked at are those
|
|
|
|
* relating to the locking protocol. Once locking is up and working,
|
|
|
|
* the sb is read again under the lock to establish the location of
|
|
|
|
* the master directory (contains pointers to journals etc) and the
|
|
|
|
* root directory.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success or error
|
|
|
|
*/
|
|
|
|
|
2011-05-10 16:01:59 +02:00
|
|
|
static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent)
|
2008-08-08 14:45:13 +02:00
|
|
|
{
|
|
|
|
struct super_block *sb = sdp->sd_vfs;
|
|
|
|
struct gfs2_sb *p;
|
|
|
|
struct page *page;
|
|
|
|
struct bio *bio;
|
|
|
|
|
|
|
|
page = alloc_page(GFP_NOFS);
|
|
|
|
if (unlikely(!page))
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
ClearPageUptodate(page);
|
|
|
|
ClearPageDirty(page);
|
|
|
|
lock_page(page);
|
|
|
|
|
|
|
|
bio = bio_alloc(GFP_NOFS, 1);
|
|
|
|
bio->bi_sector = sector * (sb->s_blocksize >> 9);
|
|
|
|
bio->bi_bdev = sb->s_bdev;
|
|
|
|
bio_add_page(bio, page, PAGE_SIZE, 0);
|
|
|
|
|
|
|
|
bio->bi_end_io = end_bio_io_page;
|
|
|
|
bio->bi_private = page;
|
2011-10-31 10:52:02 +01:00
|
|
|
submit_bio(READ_SYNC | REQ_META, bio);
|
2008-08-08 14:45:13 +02:00
|
|
|
wait_on_page_locked(page);
|
|
|
|
bio_put(bio);
|
|
|
|
if (!PageUptodate(page)) {
|
|
|
|
__free_page(page);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
p = kmap(page);
|
2011-05-10 16:01:59 +02:00
|
|
|
gfs2_sb_in(sdp, p);
|
2008-08-08 14:45:13 +02:00
|
|
|
kunmap(page);
|
|
|
|
__free_page(page);
|
2011-05-10 16:01:59 +02:00
|
|
|
return gfs2_check_sb(sdp, silent);
|
2008-08-08 14:45:13 +02:00
|
|
|
}
|
2009-03-09 10:03:51 +01:00
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
/**
|
|
|
|
* gfs2_read_sb - Read super block
|
|
|
|
* @sdp: The GFS2 superblock
|
|
|
|
* @silent: Don't print message if mount fails
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-03-09 10:03:51 +01:00
|
|
|
static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent)
|
2008-08-08 14:45:13 +02:00
|
|
|
{
|
|
|
|
u32 hash_blocks, ind_blocks, leaf_blocks;
|
|
|
|
u32 tmp_blocks;
|
|
|
|
unsigned int x;
|
|
|
|
int error;
|
|
|
|
|
2011-05-10 16:01:59 +02:00
|
|
|
error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, silent);
|
2008-08-08 14:45:13 +02:00
|
|
|
if (error) {
|
|
|
|
if (!silent)
|
|
|
|
fs_err(sdp, "can't read superblock\n");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
|
|
|
|
GFS2_BASIC_BLOCK_SHIFT;
|
|
|
|
sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
|
|
|
|
sdp->sd_diptrs = (sdp->sd_sb.sb_bsize -
|
|
|
|
sizeof(struct gfs2_dinode)) / sizeof(u64);
|
|
|
|
sdp->sd_inptrs = (sdp->sd_sb.sb_bsize -
|
|
|
|
sizeof(struct gfs2_meta_header)) / sizeof(u64);
|
|
|
|
sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
|
|
|
|
sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2;
|
|
|
|
sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1;
|
|
|
|
sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64);
|
|
|
|
sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize -
|
|
|
|
sizeof(struct gfs2_meta_header)) /
|
|
|
|
sizeof(struct gfs2_quota_change);
|
|
|
|
|
|
|
|
/* Compute maximum reservation required to add a entry to a directory */
|
|
|
|
|
|
|
|
hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH),
|
|
|
|
sdp->sd_jbsize);
|
|
|
|
|
|
|
|
ind_blocks = 0;
|
|
|
|
for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
|
|
|
|
tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs);
|
|
|
|
ind_blocks += tmp_blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH;
|
|
|
|
|
|
|
|
sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
|
|
|
|
|
|
|
|
sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize -
|
|
|
|
sizeof(struct gfs2_dinode);
|
|
|
|
sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
|
|
|
|
for (x = 2;; x++) {
|
|
|
|
u64 space, d;
|
|
|
|
u32 m;
|
|
|
|
|
|
|
|
space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
|
|
|
|
d = space;
|
|
|
|
m = do_div(d, sdp->sd_inptrs);
|
|
|
|
|
|
|
|
if (d != sdp->sd_heightsize[x - 1] || m)
|
|
|
|
break;
|
|
|
|
sdp->sd_heightsize[x] = space;
|
|
|
|
}
|
|
|
|
sdp->sd_max_height = x;
|
|
|
|
sdp->sd_heightsize[x] = ~0;
|
|
|
|
gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
|
|
|
|
|
|
|
|
sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
|
|
|
|
sizeof(struct gfs2_dinode);
|
|
|
|
sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
|
|
|
|
for (x = 2;; x++) {
|
|
|
|
u64 space, d;
|
|
|
|
u32 m;
|
|
|
|
|
|
|
|
space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
|
|
|
|
d = space;
|
|
|
|
m = do_div(d, sdp->sd_inptrs);
|
|
|
|
|
|
|
|
if (d != sdp->sd_jheightsize[x - 1] || m)
|
|
|
|
break;
|
|
|
|
sdp->sd_jheightsize[x] = space;
|
|
|
|
}
|
|
|
|
sdp->sd_max_jheight = x;
|
|
|
|
sdp->sd_jheightsize[x] = ~0;
|
|
|
|
gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
static int init_names(struct gfs2_sbd *sdp, int silent)
|
|
|
|
{
|
|
|
|
char *proto, *table;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
proto = sdp->sd_args.ar_lockproto;
|
|
|
|
table = sdp->sd_args.ar_locktable;
|
|
|
|
|
|
|
|
/* Try to autodetect */
|
|
|
|
|
|
|
|
if (!proto[0] || !table[0]) {
|
2011-05-10 16:01:59 +02:00
|
|
|
error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, silent);
|
2007-06-01 15:11:58 +02:00
|
|
|
if (error)
|
|
|
|
return error;
|
2006-10-02 17:49:41 +02:00
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!proto[0])
|
2006-10-02 17:49:41 +02:00
|
|
|
proto = sdp->sd_sb.sb_lockproto;
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!table[0])
|
2006-10-02 17:49:41 +02:00
|
|
|
table = sdp->sd_sb.sb_locktable;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!table[0])
|
|
|
|
table = sdp->sd_vfs->s_id;
|
|
|
|
|
2008-05-09 17:59:51 +02:00
|
|
|
strlcpy(sdp->sd_proto_name, proto, GFS2_FSNAME_LEN);
|
|
|
|
strlcpy(sdp->sd_table_name, table, GFS2_FSNAME_LEN);
|
2006-01-16 17:50:04 +01:00
|
|
|
|
2007-08-13 05:01:58 +02:00
|
|
|
table = sdp->sd_table_name;
|
|
|
|
while ((table = strchr(table, '/')))
|
2007-06-07 16:10:01 +02:00
|
|
|
*table = '_';
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
|
|
|
|
int undo)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (undo)
|
|
|
|
goto fail_trans;
|
|
|
|
|
|
|
|
error = gfs2_glock_nq_num(sdp,
|
|
|
|
GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
|
|
|
|
LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
|
|
|
|
mount_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't acquire mount glock: %d\n", error);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_glock_nq_num(sdp,
|
|
|
|
GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
|
|
|
|
LM_ST_SHARED,
|
2006-04-26 20:58:26 +02:00
|
|
|
LM_FLAG_NOEXP | GL_EXACT,
|
2006-01-16 17:50:04 +01:00
|
|
|
&sdp->sd_live_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't acquire live glock: %d\n", error);
|
|
|
|
goto fail_mount;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_glock_get(sdp, GFS2_RENAME_LOCK, &gfs2_nondisk_glops,
|
|
|
|
CREATE, &sdp->sd_rename_gl);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't create rename glock: %d\n", error);
|
|
|
|
goto fail_live;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops,
|
|
|
|
CREATE, &sdp->sd_trans_gl);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't create transaction glock: %d\n", error);
|
|
|
|
goto fail_rename;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
fail_trans:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_put(sdp->sd_trans_gl);
|
2006-06-14 21:32:57 +02:00
|
|
|
fail_rename:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_put(sdp->sd_rename_gl);
|
2006-06-14 21:32:57 +02:00
|
|
|
fail_live:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_dq_uninit(&sdp->sd_live_gh);
|
2006-06-14 21:32:57 +02:00
|
|
|
fail_mount:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_dq_uninit(mount_gh);
|
2006-06-14 21:32:57 +02:00
|
|
|
fail:
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr,
|
|
|
|
u64 no_addr, const char *name)
|
2006-01-30 19:34:10 +01:00
|
|
|
{
|
2008-08-08 14:45:13 +02:00
|
|
|
struct gfs2_sbd *sdp = sb->s_fs_info;
|
|
|
|
struct dentry *dentry;
|
|
|
|
struct inode *inode;
|
|
|
|
|
2011-03-17 21:19:58 +01:00
|
|
|
inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
|
2008-08-08 14:45:13 +02:00
|
|
|
if (IS_ERR(inode)) {
|
|
|
|
fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode));
|
|
|
|
return PTR_ERR(inode);
|
|
|
|
}
|
2012-01-09 04:15:13 +01:00
|
|
|
dentry = d_make_root(inode);
|
2008-08-08 14:45:13 +02:00
|
|
|
if (!dentry) {
|
|
|
|
fs_err(sdp, "can't alloc %s dentry\n", name);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
*dptr = dentry;
|
|
|
|
return 0;
|
2006-01-30 19:34:10 +01:00
|
|
|
}
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
static int init_sb(struct gfs2_sbd *sdp, int silent)
|
2006-01-16 17:50:04 +01:00
|
|
|
{
|
|
|
|
struct super_block *sb = sdp->sd_vfs;
|
|
|
|
struct gfs2_holder sb_gh;
|
2007-05-15 16:37:50 +02:00
|
|
|
u64 no_addr;
|
2008-08-08 14:45:13 +02:00
|
|
|
int ret;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
ret = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops,
|
|
|
|
LM_ST_SHARED, 0, &sb_gh);
|
|
|
|
if (ret) {
|
|
|
|
fs_err(sdp, "can't acquire superblock glock: %d\n", ret);
|
|
|
|
return ret;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
2006-09-25 15:26:04 +02:00
|
|
|
|
2009-03-09 10:03:51 +01:00
|
|
|
ret = gfs2_read_sb(sdp, silent);
|
2008-08-08 14:45:13 +02:00
|
|
|
if (ret) {
|
|
|
|
fs_err(sdp, "can't read superblock: %d\n", ret);
|
2006-01-16 17:50:04 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the buffer cache and SB for real */
|
2009-05-22 23:17:49 +02:00
|
|
|
if (sdp->sd_sb.sb_bsize < bdev_logical_block_size(sb->s_bdev)) {
|
2008-08-08 14:45:13 +02:00
|
|
|
ret = -EINVAL;
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "FS block size (%u) is too small for device "
|
|
|
|
"block size (%u)\n",
|
2009-05-22 23:17:49 +02:00
|
|
|
sdp->sd_sb.sb_bsize, bdev_logical_block_size(sb->s_bdev));
|
2006-01-16 17:50:04 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (sdp->sd_sb.sb_bsize > PAGE_SIZE) {
|
2008-08-08 14:45:13 +02:00
|
|
|
ret = -EINVAL;
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "FS block size (%u) is too big for machine "
|
|
|
|
"page size (%u)\n",
|
|
|
|
sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
sb_set_blocksize(sb, sdp->sd_sb.sb_bsize);
|
|
|
|
|
2006-01-30 19:34:10 +01:00
|
|
|
/* Get the root inode */
|
2007-05-15 16:37:50 +02:00
|
|
|
no_addr = sdp->sd_sb.sb_root_dir.no_addr;
|
2008-08-08 14:45:13 +02:00
|
|
|
ret = gfs2_lookup_root(sb, &sdp->sd_root_dir, no_addr, "root");
|
|
|
|
if (ret)
|
2006-01-30 19:34:10 +01:00
|
|
|
goto out;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
/* Get the master inode */
|
|
|
|
no_addr = sdp->sd_sb.sb_master_dir.no_addr;
|
|
|
|
ret = gfs2_lookup_root(sb, &sdp->sd_master_dir, no_addr, "master");
|
|
|
|
if (ret) {
|
|
|
|
dput(sdp->sd_root_dir);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
sb->s_root = dget(sdp->sd_args.ar_meta ? sdp->sd_master_dir : sdp->sd_root_dir);
|
2006-01-30 19:34:10 +01:00
|
|
|
out:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_dq_uninit(&sb_gh);
|
2008-08-08 14:45:13 +02:00
|
|
|
return ret;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
2007-12-12 01:49:21 +01:00
|
|
|
/**
|
|
|
|
* map_journal_extents - create a reusable "extent" mapping from all logical
|
|
|
|
* blocks to all physical blocks for the given journal. This will save
|
|
|
|
* us time when writing journal blocks. Most journals will have only one
|
|
|
|
* extent that maps all their logical blocks. That's because gfs2.mkfs
|
|
|
|
* arranges the journal blocks sequentially to maximize performance.
|
|
|
|
* So the extent would map the first block for the entire file length.
|
|
|
|
* However, gfs2_jadd can happen while file activity is happening, so
|
|
|
|
* those journals may not be sequential. Less likely is the case where
|
|
|
|
* the users created their own journals by mounting the metafs and
|
|
|
|
* laying it out. But it's still possible. These journals might have
|
|
|
|
* several extents.
|
|
|
|
*
|
|
|
|
* TODO: This should be done in bigger chunks rather than one block at a time,
|
|
|
|
* but since it's only done at mount time, I'm not worried about the
|
|
|
|
* time it takes.
|
|
|
|
*/
|
|
|
|
static int map_journal_extents(struct gfs2_sbd *sdp)
|
|
|
|
{
|
|
|
|
struct gfs2_jdesc *jd = sdp->sd_jdesc;
|
|
|
|
unsigned int lb;
|
|
|
|
u64 db, prev_db; /* logical block, disk block, prev disk block */
|
|
|
|
struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
|
|
|
|
struct gfs2_journal_extent *jext = NULL;
|
|
|
|
struct buffer_head bh;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
prev_db = 0;
|
|
|
|
|
2010-08-11 10:53:11 +02:00
|
|
|
for (lb = 0; lb < i_size_read(jd->jd_inode) >> sdp->sd_sb.sb_bsize_shift; lb++) {
|
2007-12-12 01:49:21 +01:00
|
|
|
bh.b_state = 0;
|
|
|
|
bh.b_blocknr = 0;
|
|
|
|
bh.b_size = 1 << ip->i_inode.i_blkbits;
|
|
|
|
rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
|
|
|
|
db = bh.b_blocknr;
|
|
|
|
if (rc || !db) {
|
|
|
|
printk(KERN_INFO "GFS2 journal mapping error %d: lb="
|
|
|
|
"%u db=%llu\n", rc, lb, (unsigned long long)db);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!prev_db || db != prev_db + 1) {
|
|
|
|
jext = kzalloc(sizeof(struct gfs2_journal_extent),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!jext) {
|
|
|
|
printk(KERN_INFO "GFS2 error: out of memory "
|
|
|
|
"mapping journal extents.\n");
|
|
|
|
rc = -ENOMEM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
jext->dblock = db;
|
|
|
|
jext->lblock = lb;
|
|
|
|
jext->blocks = 1;
|
|
|
|
list_add_tail(&jext->extent_list, &jd->extent_list);
|
|
|
|
} else {
|
|
|
|
jext->blocks++;
|
|
|
|
}
|
|
|
|
prev_db = db;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
|
2008-01-30 16:34:04 +01:00
|
|
|
{
|
2009-01-12 11:43:39 +01:00
|
|
|
char *message = "FIRSTMOUNT=Done";
|
|
|
|
char *envp[] = { message, NULL };
|
2012-01-09 23:18:05 +01:00
|
|
|
|
|
|
|
fs_info(sdp, "first mount done, others may mount\n");
|
|
|
|
|
|
|
|
if (sdp->sd_lockstruct.ls_ops->lm_first_done)
|
|
|
|
sdp->sd_lockstruct.ls_ops->lm_first_done(sdp);
|
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
|
2008-01-30 16:34:04 +01:00
|
|
|
}
|
|
|
|
|
2008-11-26 13:49:26 +01:00
|
|
|
/**
|
|
|
|
* 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);
|
2010-07-20 22:09:02 +02:00
|
|
|
INIT_WORK(&jd->jd_work, gfs2_recover_func);
|
2008-11-26 13:49:26 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|
|
|
{
|
2008-08-08 14:45:13 +02:00
|
|
|
struct inode *master = sdp->sd_master_dir->d_inode;
|
2006-01-16 17:50:04 +01:00
|
|
|
struct gfs2_holder ji_gh;
|
2006-02-27 23:23:27 +01:00
|
|
|
struct gfs2_inode *ip;
|
2006-01-16 17:50:04 +01:00
|
|
|
int jindex = 1;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (undo) {
|
|
|
|
jindex = 0;
|
2009-05-19 11:01:18 +02:00
|
|
|
goto fail_jinode_gh;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
sdp->sd_jindex = gfs2_lookup_simple(master, "jindex");
|
2006-03-20 18:30:04 +01:00
|
|
|
if (IS_ERR(sdp->sd_jindex)) {
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't lookup journal index: %d\n", error);
|
2006-03-20 18:30:04 +01:00
|
|
|
return PTR_ERR(sdp->sd_jindex);
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Load in the journal index special file */
|
|
|
|
|
|
|
|
error = gfs2_jindex_hold(sdp, &ji_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't read journal index: %d\n", error);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2010-02-06 00:25:41 +01:00
|
|
|
error = -EUSERS;
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!gfs2_jindex_size(sdp)) {
|
|
|
|
fs_err(sdp, "no journals!\n");
|
2006-09-25 15:26:04 +02:00
|
|
|
goto fail_jindex;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sdp->sd_args.ar_spectator) {
|
|
|
|
sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
|
2007-11-08 15:55:03 +01:00
|
|
|
atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
atomic_set(&sdp->sd_log_thresh1, 2*sdp->sd_jdesc->jd_blocks/5);
|
|
|
|
atomic_set(&sdp->sd_log_thresh2, 4*sdp->sd_jdesc->jd_blocks/5);
|
2006-01-16 17:50:04 +01:00
|
|
|
} else {
|
|
|
|
if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
|
|
|
|
fs_err(sdp, "can't mount journal #%u\n",
|
|
|
|
sdp->sd_lockstruct.ls_jid);
|
|
|
|
fs_err(sdp, "there are only %u journals (0 - %u)\n",
|
|
|
|
gfs2_jindex_size(sdp),
|
|
|
|
gfs2_jindex_size(sdp) - 1);
|
|
|
|
goto fail_jindex;
|
|
|
|
}
|
|
|
|
sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid);
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
|
2006-01-16 17:50:04 +01:00
|
|
|
&gfs2_journal_glops,
|
|
|
|
LM_ST_EXCLUSIVE, LM_FLAG_NOEXP,
|
|
|
|
&sdp->sd_journal_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't acquire journal glock: %d\n", error);
|
|
|
|
goto fail_jindex;
|
|
|
|
}
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
ip = GFS2_I(sdp->sd_jdesc->jd_inode);
|
|
|
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
2007-08-09 00:08:14 +02:00
|
|
|
LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE,
|
2006-01-16 17:50:04 +01:00
|
|
|
&sdp->sd_jinode_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't acquire journal inode glock: %d\n",
|
|
|
|
error);
|
|
|
|
goto fail_journal_gh;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_jdesc_check(sdp->sd_jdesc);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "my journal (%u) is bad: %d\n",
|
|
|
|
sdp->sd_jdesc->jd_jid, error);
|
|
|
|
goto fail_jinode_gh;
|
|
|
|
}
|
2007-11-08 15:55:03 +01:00
|
|
|
atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
atomic_set(&sdp->sd_log_thresh1, 2*sdp->sd_jdesc->jd_blocks/5);
|
|
|
|
atomic_set(&sdp->sd_log_thresh2, 4*sdp->sd_jdesc->jd_blocks/5);
|
2007-12-12 01:49:21 +01:00
|
|
|
|
|
|
|
/* Map the extents for this journal's blocks */
|
|
|
|
map_journal_extents(sdp);
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
2009-06-12 09:49:20 +02:00
|
|
|
trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free));
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
if (sdp->sd_lockstruct.ls_first) {
|
|
|
|
unsigned int x;
|
|
|
|
for (x = 0; x < sdp->sd_journals; x++) {
|
2010-07-20 22:09:02 +02:00
|
|
|
error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
|
|
|
|
true);
|
2006-01-16 17:50:04 +01:00
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "error recovering journal %u: %d\n",
|
|
|
|
x, error);
|
|
|
|
goto fail_jinode_gh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
gfs2_others_may_mount(sdp);
|
2006-01-16 17:50:04 +01:00
|
|
|
} else if (!sdp->sd_args.ar_spectator) {
|
2010-07-20 22:09:02 +02:00
|
|
|
error = gfs2_recover_journal(sdp->sd_jdesc, true);
|
2006-01-16 17:50:04 +01:00
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "error recovering my journal: %d\n", error);
|
|
|
|
goto fail_jinode_gh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
|
|
|
|
gfs2_glock_dq_uninit(&ji_gh);
|
|
|
|
jindex = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_jinode_gh:
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!sdp->sd_args.ar_spectator)
|
|
|
|
gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_journal_gh:
|
2006-01-16 17:50:04 +01:00
|
|
|
if (!sdp->sd_args.ar_spectator)
|
|
|
|
gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_jindex:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_jindex_free(sdp);
|
|
|
|
if (jindex)
|
|
|
|
gfs2_glock_dq_uninit(&ji_gh);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail:
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(sdp->sd_jindex);
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int init_inodes(struct gfs2_sbd *sdp, int undo)
|
|
|
|
{
|
|
|
|
int error = 0;
|
2008-08-08 14:45:13 +02:00
|
|
|
struct inode *master = sdp->sd_master_dir->d_inode;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
if (undo)
|
2006-01-30 19:34:10 +01:00
|
|
|
goto fail_qinode;
|
|
|
|
|
|
|
|
error = init_journal(sdp, undo);
|
|
|
|
if (error)
|
2008-08-08 14:45:13 +02:00
|
|
|
goto fail;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
/* Read in the master statfs inode */
|
2008-08-08 14:45:13 +02:00
|
|
|
sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs");
|
2006-03-20 18:30:04 +01:00
|
|
|
if (IS_ERR(sdp->sd_statfs_inode)) {
|
|
|
|
error = PTR_ERR(sdp->sd_statfs_inode);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't read in statfs inode: %d\n", error);
|
2009-08-27 16:51:07 +02:00
|
|
|
goto fail_journal;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in the resource index inode */
|
2008-08-08 14:45:13 +02:00
|
|
|
sdp->sd_rindex = gfs2_lookup_simple(master, "rindex");
|
2006-03-20 18:30:04 +01:00
|
|
|
if (IS_ERR(sdp->sd_rindex)) {
|
|
|
|
error = PTR_ERR(sdp->sd_rindex);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't get resource index inode: %d\n", error);
|
|
|
|
goto fail_statfs;
|
|
|
|
}
|
2008-01-31 17:31:39 +01:00
|
|
|
sdp->sd_rindex_uptodate = 0;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
/* Read in the quota inode */
|
2008-08-08 14:45:13 +02:00
|
|
|
sdp->sd_quota_inode = gfs2_lookup_simple(master, "quota");
|
2006-03-20 18:30:04 +01:00
|
|
|
if (IS_ERR(sdp->sd_quota_inode)) {
|
|
|
|
error = PTR_ERR(sdp->sd_quota_inode);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't get quota file inode: %d\n", error);
|
|
|
|
goto fail_rindex;
|
|
|
|
}
|
2012-02-24 16:09:14 +01:00
|
|
|
|
|
|
|
error = gfs2_rindex_update(sdp);
|
|
|
|
if (error)
|
|
|
|
goto fail_qinode;
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2006-01-30 19:34:10 +01:00
|
|
|
fail_qinode:
|
|
|
|
iput(sdp->sd_quota_inode);
|
|
|
|
fail_rindex:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_clear_rgrpd(sdp);
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(sdp->sd_rindex);
|
|
|
|
fail_statfs:
|
|
|
|
iput(sdp->sd_statfs_inode);
|
|
|
|
fail_journal:
|
|
|
|
init_journal(sdp, UNDO);
|
|
|
|
fail:
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int init_per_node(struct gfs2_sbd *sdp, int undo)
|
|
|
|
{
|
2006-01-30 19:34:10 +01:00
|
|
|
struct inode *pn = NULL;
|
2006-01-16 17:50:04 +01:00
|
|
|
char buf[30];
|
|
|
|
int error = 0;
|
2006-02-27 23:23:27 +01:00
|
|
|
struct gfs2_inode *ip;
|
2008-08-08 14:45:13 +02:00
|
|
|
struct inode *master = sdp->sd_master_dir->d_inode;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
if (sdp->sd_args.ar_spectator)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (undo)
|
|
|
|
goto fail_qc_gh;
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
pn = gfs2_lookup_simple(master, "per_node");
|
2006-03-20 18:30:04 +01:00
|
|
|
if (IS_ERR(pn)) {
|
|
|
|
error = PTR_ERR(pn);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't find per_node directory: %d\n", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
|
2006-03-20 18:30:04 +01:00
|
|
|
sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
|
|
|
|
if (IS_ERR(sdp->sd_sc_inode)) {
|
|
|
|
error = PTR_ERR(sdp->sd_sc_inode);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
|
2009-08-27 16:51:07 +02:00
|
|
|
goto fail;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
|
2006-03-20 18:30:04 +01:00
|
|
|
sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
|
|
|
|
if (IS_ERR(sdp->sd_qc_inode)) {
|
|
|
|
error = PTR_ERR(sdp->sd_qc_inode);
|
2006-01-16 17:50:04 +01:00
|
|
|
fs_err(sdp, "can't find local \"qc\" file: %d\n", error);
|
|
|
|
goto fail_ut_i;
|
|
|
|
}
|
|
|
|
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(pn);
|
2006-01-16 17:50:04 +01:00
|
|
|
pn = NULL;
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
ip = GFS2_I(sdp->sd_sc_inode);
|
2009-08-27 16:51:07 +02:00
|
|
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
|
2006-01-16 17:50:04 +01:00
|
|
|
&sdp->sd_sc_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
|
2009-08-27 16:51:07 +02:00
|
|
|
goto fail_qc_i;
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
ip = GFS2_I(sdp->sd_qc_inode);
|
2009-08-27 16:51:07 +02:00
|
|
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
|
2006-01-16 17:50:04 +01:00
|
|
|
&sdp->sd_qc_gh);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
|
|
|
|
goto fail_ut_gh;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_qc_gh:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_ut_gh:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_qc_i:
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(sdp->sd_qc_inode);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_ut_i:
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(sdp->sd_sc_inode);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail:
|
2006-01-16 17:50:04 +01:00
|
|
|
if (pn)
|
2006-01-30 19:34:10 +01:00
|
|
|
iput(pn);
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int init_threads(struct gfs2_sbd *sdp, int undo)
|
|
|
|
{
|
|
|
|
struct task_struct *p;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (undo)
|
2006-06-14 21:32:57 +02:00
|
|
|
goto fail_quotad;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
|
|
|
|
error = IS_ERR(p);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't start logd thread: %d\n", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
sdp->sd_logd_process = p;
|
|
|
|
|
|
|
|
p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
|
|
|
|
error = IS_ERR(p);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't start quotad thread: %d\n", error);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
sdp->sd_quotad_process = p;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
2006-06-14 21:32:57 +02:00
|
|
|
fail_quotad:
|
2006-01-16 17:50:04 +01:00
|
|
|
kthread_stop(sdp->sd_quotad_process);
|
2006-06-14 21:32:57 +02:00
|
|
|
fail:
|
2006-01-16 17:50:04 +01:00
|
|
|
kthread_stop(sdp->sd_logd_process);
|
|
|
|
return error;
|
|
|
|
}
|
2008-01-30 16:34:04 +01:00
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
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",
|
2011-03-09 11:58:04 +01:00
|
|
|
.lm_put_lock = gfs2_glock_free,
|
2009-01-12 11:43:39 +01:00
|
|
|
.lm_tokens = &nolock_tokens,
|
|
|
|
};
|
|
|
|
|
2008-01-30 16:34:04 +01:00
|
|
|
/**
|
|
|
|
* gfs2_lm_mount - mount a locking protocol
|
|
|
|
* @sdp: the filesystem
|
tree-wide: Assorted spelling fixes
In particular, several occurances of funny versions of 'success',
'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address',
'beginning', 'desirable', 'separate' and 'necessary' are fixed.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Joe Perches <joe@perches.com>
Cc: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-02-03 01:01:28 +01:00
|
|
|
* @args: mount arguments
|
2008-01-30 16:34:04 +01:00
|
|
|
* @silent: if 1, don't complain if the FS isn't a GFS2 fs
|
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
|
|
|
|
{
|
2009-01-12 11:43:39 +01:00
|
|
|
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;
|
|
|
|
char *o, *options;
|
|
|
|
int ret;
|
2008-01-30 16:34:04 +01:00
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
if (!strcmp("lock_nolock", proto)) {
|
|
|
|
lm = &nolock_ops;
|
|
|
|
sdp->sd_args.ar_localflocks = 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;
|
|
|
|
}
|
2008-01-30 16:34:04 +01:00
|
|
|
|
|
|
|
fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
|
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
ls->ls_ops = lm;
|
|
|
|
ls->ls_first = 1;
|
2008-01-30 16:34:04 +01:00
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
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;
|
2010-06-14 11:01:30 +02:00
|
|
|
if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags))
|
|
|
|
ls->ls_jid = option;
|
2009-01-12 11:43:39 +01:00
|
|
|
break;
|
|
|
|
case Opt_id:
|
2009-09-09 16:59:35 +02:00
|
|
|
/* Obsolete, but left for backward compat purposes */
|
2009-01-12 11:43:39 +01:00
|
|
|
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;
|
|
|
|
}
|
2008-01-30 16:34:04 +01:00
|
|
|
}
|
|
|
|
|
2009-01-12 11:43:39 +01:00
|
|
|
if (lm->lm_mount == NULL) {
|
|
|
|
fs_info(sdp, "Now mounting FS...\n");
|
2011-07-26 10:15:45 +02:00
|
|
|
complete_all(&sdp->sd_locking_init);
|
2009-01-12 11:43:39 +01:00
|
|
|
return 0;
|
2008-01-30 16:34:04 +01:00
|
|
|
}
|
2012-01-09 23:18:05 +01:00
|
|
|
ret = lm->lm_mount(sdp, table);
|
2009-01-12 11:43:39 +01:00
|
|
|
if (ret == 0)
|
|
|
|
fs_info(sdp, "Joined cluster. Now mounting FS...\n");
|
2011-07-26 10:15:45 +02:00
|
|
|
complete_all(&sdp->sd_locking_init);
|
2009-01-12 11:43:39 +01:00
|
|
|
return ret;
|
2008-01-30 16:34:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void gfs2_lm_unmount(struct gfs2_sbd *sdp)
|
|
|
|
{
|
2009-01-12 11:43:39 +01:00
|
|
|
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);
|
2008-01-30 16:34:04 +01:00
|
|
|
}
|
2006-01-16 17:50:04 +01:00
|
|
|
|
2010-06-14 11:01:30 +02:00
|
|
|
static int gfs2_journalid_wait(void *word)
|
|
|
|
{
|
|
|
|
if (signal_pending(current))
|
|
|
|
return -EINTR;
|
|
|
|
schedule();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wait_on_journal(struct gfs2_sbd *sdp)
|
|
|
|
{
|
|
|
|
if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return wait_on_bit(&sdp->sd_flags, SDF_NOJOURNALID, gfs2_journalid_wait, TASK_INTERRUPTIBLE);
|
|
|
|
}
|
|
|
|
|
2009-07-31 12:07:29 +02:00
|
|
|
void gfs2_online_uevent(struct gfs2_sbd *sdp)
|
|
|
|
{
|
|
|
|
struct super_block *sb = sdp->sd_vfs;
|
|
|
|
char ro[20];
|
|
|
|
char spectator[20];
|
|
|
|
char *envp[] = { ro, spectator, NULL };
|
|
|
|
sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
|
|
|
|
sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
|
|
|
|
kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp);
|
|
|
|
}
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
/**
|
|
|
|
* fill_super - Read in superblock
|
|
|
|
* @sb: The VFS superblock
|
|
|
|
* @data: Mount options
|
|
|
|
* @silent: Don't complain if it's not a GFS2 filesystem
|
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
2009-09-28 11:30:49 +02:00
|
|
|
static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent)
|
2006-01-16 17:50:04 +01:00
|
|
|
{
|
|
|
|
struct gfs2_sbd *sdp;
|
|
|
|
struct gfs2_holder mount_gh;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
sdp = init_sbd(sb);
|
|
|
|
if (!sdp) {
|
2006-02-27 16:57:14 +01:00
|
|
|
printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
|
2006-01-16 17:50:04 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2009-09-28 11:30:49 +02:00
|
|
|
sdp->sd_args = *args;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
2009-05-19 11:01:18 +02:00
|
|
|
if (sdp->sd_args.ar_spectator) {
|
2009-01-06 12:52:25 +01:00
|
|
|
sb->s_flags |= MS_RDONLY;
|
2012-01-09 20:40:06 +01:00
|
|
|
set_bit(SDF_RORECOVERY, &sdp->sd_flags);
|
2009-05-19 11:01:18 +02:00
|
|
|
}
|
2009-01-06 12:52:25 +01:00
|
|
|
if (sdp->sd_args.ar_posix_acl)
|
|
|
|
sb->s_flags |= MS_POSIXACL;
|
2009-10-30 08:03:27 +01:00
|
|
|
if (sdp->sd_args.ar_nobarrier)
|
|
|
|
set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
|
2009-01-06 12:52:25 +01:00
|
|
|
|
2011-06-16 15:06:55 +02:00
|
|
|
sb->s_flags |= MS_NOSEC;
|
2008-09-18 14:53:59 +02:00
|
|
|
sb->s_magic = GFS2_MAGIC;
|
|
|
|
sb->s_op = &gfs2_super_ops;
|
2010-12-18 18:06:56 +01:00
|
|
|
sb->s_d_op = &gfs2_dops;
|
2008-09-18 14:53:59 +02:00
|
|
|
sb->s_export_op = &gfs2_export_ops;
|
2009-08-26 19:41:32 +02:00
|
|
|
sb->s_xattr = gfs2_xattr_handlers;
|
2009-09-15 10:59:02 +02:00
|
|
|
sb->s_qcop = &gfs2_quotactl_ops;
|
|
|
|
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
|
2008-09-18 14:53:59 +02:00
|
|
|
sb->s_time_gran = 1;
|
|
|
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
2006-03-02 22:33:41 +01:00
|
|
|
|
|
|
|
/* Set up the buffer cache and fill in some fake block size values
|
|
|
|
to allow us to read-in the on-disk superblock. */
|
|
|
|
sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS2_BASIC_BLOCK);
|
|
|
|
sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits;
|
|
|
|
sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
|
|
|
|
GFS2_BASIC_BLOCK_SHIFT;
|
|
|
|
sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
sdp->sd_tune.gt_logd_secs = sdp->sd_args.ar_commit;
|
2009-10-20 09:39:44 +02:00
|
|
|
sdp->sd_tune.gt_quota_quantum = sdp->sd_args.ar_quota_quantum;
|
|
|
|
if (sdp->sd_args.ar_statfs_quantum) {
|
|
|
|
sdp->sd_tune.gt_statfs_slow = 0;
|
|
|
|
sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum;
|
2011-05-10 16:01:59 +02:00
|
|
|
} else {
|
2009-10-20 09:39:44 +02:00
|
|
|
sdp->sd_tune.gt_statfs_slow = 1;
|
|
|
|
sdp->sd_tune.gt_statfs_quantum = 30;
|
|
|
|
}
|
2009-05-13 15:49:48 +02:00
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
error = init_names(sdp, silent);
|
|
|
|
if (error)
|
|
|
|
goto fail;
|
|
|
|
|
2012-01-09 23:18:05 +01:00
|
|
|
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name);
|
|
|
|
|
2007-03-16 11:26:37 +01:00
|
|
|
gfs2_create_debugfs_file(sdp);
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
error = gfs2_sys_fs_add(sdp);
|
|
|
|
if (error)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
error = gfs2_lm_mount(sdp, silent);
|
|
|
|
if (error)
|
|
|
|
goto fail_sys;
|
|
|
|
|
|
|
|
error = init_locking(sdp, &mount_gh, DO);
|
|
|
|
if (error)
|
|
|
|
goto fail_lm;
|
|
|
|
|
2008-08-08 14:45:13 +02:00
|
|
|
error = init_sb(sdp, silent);
|
2006-01-16 17:50:04 +01:00
|
|
|
if (error)
|
|
|
|
goto fail_locking;
|
|
|
|
|
2010-06-14 11:01:30 +02:00
|
|
|
error = wait_on_journal(sdp);
|
|
|
|
if (error)
|
|
|
|
goto fail_sb;
|
|
|
|
|
2010-09-29 16:04:18 +02:00
|
|
|
/*
|
|
|
|
* If user space has failed to join the cluster or some similar
|
|
|
|
* failure has occurred, then the journal id will contain a
|
|
|
|
* negative (error) number. This will then be returned to the
|
|
|
|
* caller (of the mount syscall). We do this even for spectator
|
|
|
|
* mounts (which just write a jid of 0 to indicate "ok" even though
|
|
|
|
* the jid is unused in the spectator case)
|
|
|
|
*/
|
|
|
|
if (sdp->sd_lockstruct.ls_jid < 0) {
|
|
|
|
error = sdp->sd_lockstruct.ls_jid;
|
|
|
|
sdp->sd_lockstruct.ls_jid = 0;
|
|
|
|
goto fail_sb;
|
|
|
|
}
|
|
|
|
|
2012-01-09 23:18:05 +01:00
|
|
|
if (sdp->sd_args.ar_spectator)
|
|
|
|
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s",
|
|
|
|
sdp->sd_table_name);
|
|
|
|
else
|
|
|
|
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u",
|
|
|
|
sdp->sd_table_name, sdp->sd_lockstruct.ls_jid);
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
error = init_inodes(sdp, DO);
|
|
|
|
if (error)
|
2006-01-30 19:34:10 +01:00
|
|
|
goto fail_sb;
|
2006-01-16 17:50:04 +01:00
|
|
|
|
|
|
|
error = init_per_node(sdp, DO);
|
|
|
|
if (error)
|
|
|
|
goto fail_inodes;
|
|
|
|
|
|
|
|
error = gfs2_statfs_init(sdp);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't initialize statfs subsystem: %d\n", error);
|
|
|
|
goto fail_per_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = init_threads(sdp, DO);
|
|
|
|
if (error)
|
|
|
|
goto fail_per_node;
|
|
|
|
|
|
|
|
if (!(sb->s_flags & MS_RDONLY)) {
|
|
|
|
error = gfs2_make_fs_rw(sdp);
|
|
|
|
if (error) {
|
|
|
|
fs_err(sdp, "can't make FS RW: %d\n", error);
|
|
|
|
goto fail_threads;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gfs2_glock_dq_uninit(&mount_gh);
|
2009-07-31 12:07:29 +02:00
|
|
|
gfs2_online_uevent(sdp);
|
2006-01-16 17:50:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_threads:
|
2006-01-16 17:50:04 +01:00
|
|
|
init_threads(sdp, UNDO);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_per_node:
|
2006-01-16 17:50:04 +01:00
|
|
|
init_per_node(sdp, UNDO);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_inodes:
|
2006-01-16 17:50:04 +01:00
|
|
|
init_inodes(sdp, UNDO);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_sb:
|
2008-08-08 14:45:13 +02:00
|
|
|
if (sdp->sd_root_dir)
|
|
|
|
dput(sdp->sd_root_dir);
|
|
|
|
if (sdp->sd_master_dir)
|
|
|
|
dput(sdp->sd_master_dir);
|
2009-01-20 17:39:23 +01:00
|
|
|
if (sb->s_root)
|
|
|
|
dput(sb->s_root);
|
2008-08-08 14:45:13 +02:00
|
|
|
sb->s_root = NULL;
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_locking:
|
2006-01-16 17:50:04 +01:00
|
|
|
init_locking(sdp, &mount_gh, UNDO);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_lm:
|
2008-12-19 16:32:06 +01:00
|
|
|
gfs2_gl_hash_clear(sdp);
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_lm_unmount(sdp);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail_sys:
|
2006-01-16 17:50:04 +01:00
|
|
|
gfs2_sys_fs_del(sdp);
|
2006-09-04 18:04:26 +02:00
|
|
|
fail:
|
2007-04-18 18:41:11 +02:00
|
|
|
gfs2_delete_debugfs_file(sdp);
|
GFS2: glock statistics gathering
The stats are divided into two sets: those relating to the
super block and those relating to an individual glock. The
super block stats are done on a per cpu basis in order to
try and reduce the overhead of gathering them. They are also
further divided by glock type.
In the case of both the super block and glock statistics,
the same information is gathered in each case. The super
block statistics are used to provide default values for
most of the glock statistics, so that newly created glocks
should have, as far as possible, a sensible starting point.
The statistics are divided into three pairs of mean and
variance, plus two counters. The mean/variance pairs are
smoothed exponential estimates and the algorithm used is
one which will be very familiar to those used to calculation
of round trip times in network code.
The three pairs of mean/variance measure the following
things:
1. DLM lock time (non-blocking requests)
2. DLM lock time (blocking requests)
3. Inter-request time (again to the DLM)
A non-blocking request is one which will complete right
away, whatever the state of the DLM lock in question. That
currently means any requests when (a) the current state of
the lock is exclusive (b) the requested state is either null
or unlocked or (c) the "try lock" flag is set. A blocking
request covers all the other lock requests.
There are two counters. The first is there primarily to show
how many lock requests have been made, and thus how much data
has gone into the mean/variance calculations. The other counter
is counting queueing of holders at the top layer of the glock
code. Hopefully that number will be a lot larger than the number
of dlm lock requests issued.
So why gather these statistics? There are several reasons
we'd like to get a better idea of these timings:
1. To be able to better set the glock "min hold time"
2. To spot performance issues more easily
3. To improve the algorithm for selecting resource groups for
allocation (to base it on lock wait time, rather than blindly
using a "try lock")
Due to the smoothing action of the updates, a step change in
some input quantity being sampled will only fully be taken
into account after 8 samples (or 4 for the variance) and this
needs to be carefully considered when interpreting the
results.
Knowing both the time it takes a lock request to complete and
the average time between lock requests for a glock means we
can compute the total percentage of the time for which the
node is able to use a glock vs. time that the rest of the
cluster has its share. That will be very useful when setting
the lock min hold time.
The other point to remember is that all times are in
nanoseconds. Great care has been taken to ensure that we
measure exactly the quantities that we want, as accurately
as possible. There are always inaccuracies in any
measuring system, but I hope this is as accurate as we
can reasonably make it.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2012-01-20 11:38:36 +01:00
|
|
|
free_percpu(sdp->sd_lkstats);
|
2006-09-08 16:13:03 +02:00
|
|
|
kfree(sdp);
|
2006-02-27 23:23:27 +01:00
|
|
|
sb->s_fs_info = NULL;
|
2006-01-16 17:50:04 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2009-09-28 11:30:49 +02:00
|
|
|
static int set_gfs2_super(struct super_block *s, void *data)
|
2006-01-16 17:50:04 +01:00
|
|
|
{
|
2009-09-28 11:30:49 +02:00
|
|
|
s->s_bdev = data;
|
|
|
|
s->s_dev = s->s_bdev->bd_dev;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We set the bdi here to the queue backing, file systems can
|
|
|
|
* overwrite this in ->fill_super()
|
|
|
|
*/
|
|
|
|
s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
|
|
|
|
return 0;
|
2006-08-25 18:13:37 +02:00
|
|
|
}
|
|
|
|
|
2009-09-28 11:30:49 +02:00
|
|
|
static int test_gfs2_super(struct super_block *s, void *ptr)
|
2009-06-05 08:18:57 +02:00
|
|
|
{
|
|
|
|
struct block_device *bdev = ptr;
|
|
|
|
return (bdev == s->s_bdev);
|
|
|
|
}
|
|
|
|
|
2009-09-28 11:30:49 +02:00
|
|
|
/**
|
2010-07-26 14:03:58 +02:00
|
|
|
* gfs2_mount - Get the GFS2 superblock
|
2009-09-28 11:30:49 +02:00
|
|
|
* @fs_type: The GFS2 filesystem type
|
|
|
|
* @flags: Mount flags
|
|
|
|
* @dev_name: The name of the device
|
|
|
|
* @data: The mount arguments
|
|
|
|
*
|
|
|
|
* Q. Why not use get_sb_bdev() ?
|
|
|
|
* A. We need to select one of two root directories to mount, independent
|
|
|
|
* of whether this is the initial, or subsequent, mount of this sb
|
|
|
|
*
|
|
|
|
* Returns: 0 or -ve on error
|
|
|
|
*/
|
|
|
|
|
2010-07-26 14:03:58 +02:00
|
|
|
static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
|
|
|
|
const char *dev_name, void *data)
|
2009-09-28 11:30:49 +02:00
|
|
|
{
|
|
|
|
struct block_device *bdev;
|
|
|
|
struct super_block *s;
|
2010-11-13 11:55:18 +01:00
|
|
|
fmode_t mode = FMODE_READ | FMODE_EXCL;
|
2009-09-28 11:30:49 +02:00
|
|
|
int error;
|
|
|
|
struct gfs2_args args;
|
|
|
|
struct gfs2_sbd *sdp;
|
|
|
|
|
|
|
|
if (!(flags & MS_RDONLY))
|
|
|
|
mode |= FMODE_WRITE;
|
|
|
|
|
2010-11-13 11:55:18 +01:00
|
|
|
bdev = blkdev_get_by_path(dev_name, mode, fs_type);
|
2009-09-28 11:30:49 +02:00
|
|
|
if (IS_ERR(bdev))
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_CAST(bdev);
|
2009-09-28 11:30:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* once the super is inserted into the list by sget, s_umount
|
|
|
|
* will protect the lockfs code from trying to start a snapshot
|
|
|
|
* while we are mounting
|
|
|
|
*/
|
|
|
|
mutex_lock(&bdev->bd_fsfreeze_mutex);
|
|
|
|
if (bdev->bd_fsfreeze_count > 0) {
|
|
|
|
mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
|
|
|
error = -EBUSY;
|
|
|
|
goto error_bdev;
|
|
|
|
}
|
|
|
|
s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
|
|
|
|
mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
|
|
|
error = PTR_ERR(s);
|
|
|
|
if (IS_ERR(s))
|
|
|
|
goto error_bdev;
|
|
|
|
|
2010-07-26 14:03:58 +02:00
|
|
|
if (s->s_root)
|
2010-11-13 11:55:18 +01:00
|
|
|
blkdev_put(bdev, mode);
|
2010-07-26 14:03:58 +02:00
|
|
|
|
2009-09-28 11:30:49 +02:00
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
args.ar_quota = GFS2_QUOTA_DEFAULT;
|
|
|
|
args.ar_data = GFS2_DATA_DEFAULT;
|
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 21:29:16 +02:00
|
|
|
args.ar_commit = 30;
|
2009-10-20 09:39:44 +02:00
|
|
|
args.ar_statfs_quantum = 30;
|
|
|
|
args.ar_quota_quantum = 60;
|
2009-09-28 11:30:49 +02:00
|
|
|
args.ar_errors = GFS2_ERRORS_DEFAULT;
|
|
|
|
|
|
|
|
error = gfs2_mount_args(&args, data);
|
|
|
|
if (error) {
|
|
|
|
printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
|
2010-07-26 14:03:58 +02:00
|
|
|
goto error_super;
|
2009-09-28 11:30:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (s->s_root) {
|
|
|
|
error = -EBUSY;
|
|
|
|
if ((flags ^ s->s_flags) & MS_RDONLY)
|
|
|
|
goto error_super;
|
|
|
|
} else {
|
|
|
|
char b[BDEVNAME_SIZE];
|
|
|
|
|
|
|
|
s->s_flags = flags;
|
|
|
|
s->s_mode = mode;
|
|
|
|
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
|
|
|
|
sb_set_blocksize(s, block_size(bdev));
|
|
|
|
error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
|
2010-07-26 14:03:58 +02:00
|
|
|
if (error)
|
|
|
|
goto error_super;
|
2009-09-28 11:30:49 +02:00
|
|
|
s->s_flags |= MS_ACTIVE;
|
|
|
|
bdev->bd_super = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdp = s->s_fs_info;
|
|
|
|
if (args.ar_meta)
|
2010-07-26 14:03:58 +02:00
|
|
|
return dget(sdp->sd_master_dir);
|
2009-09-28 11:30:49 +02:00
|
|
|
else
|
2010-07-26 14:03:58 +02:00
|
|
|
return dget(sdp->sd_root_dir);
|
2009-09-28 11:30:49 +02:00
|
|
|
|
|
|
|
error_super:
|
|
|
|
deactivate_locked_super(s);
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_PTR(error);
|
2009-09-28 11:30:49 +02:00
|
|
|
error_bdev:
|
2010-11-13 11:55:18 +01:00
|
|
|
blkdev_put(bdev, mode);
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_PTR(error);
|
2009-09-28 11:30:49 +02:00
|
|
|
}
|
|
|
|
|
2009-06-05 08:18:57 +02:00
|
|
|
static int set_meta_super(struct super_block *s, void *ptr)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2010-07-26 14:03:58 +02:00
|
|
|
static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type,
|
|
|
|
int flags, const char *dev_name, void *data)
|
2006-08-25 18:13:37 +02:00
|
|
|
{
|
2009-06-05 08:18:57 +02:00
|
|
|
struct super_block *s;
|
2009-06-10 11:31:45 +02:00
|
|
|
struct gfs2_sbd *sdp;
|
2009-04-03 03:17:03 +02:00
|
|
|
struct path path;
|
2006-08-25 18:13:37 +02:00
|
|
|
int error;
|
2006-09-25 15:26:04 +02:00
|
|
|
|
2009-04-03 03:17:03 +02:00
|
|
|
error = kern_path(dev_name, LOOKUP_FOLLOW, &path);
|
2006-08-25 18:13:37 +02:00
|
|
|
if (error) {
|
2008-08-08 14:45:13 +02:00
|
|
|
printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n",
|
|
|
|
dev_name, error);
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_PTR(error);
|
2006-08-25 18:13:37 +02:00
|
|
|
}
|
2009-09-28 11:30:49 +02:00
|
|
|
s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
|
2009-06-05 08:18:57 +02:00
|
|
|
path.dentry->d_inode->i_sb->s_bdev);
|
2009-04-03 03:17:03 +02:00
|
|
|
path_put(&path);
|
2009-06-05 08:18:57 +02:00
|
|
|
if (IS_ERR(s)) {
|
2006-08-25 18:13:37 +02:00
|
|
|
printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_CAST(s);
|
2006-08-25 18:13:37 +02:00
|
|
|
}
|
2009-09-28 11:30:49 +02:00
|
|
|
if ((flags ^ s->s_flags) & MS_RDONLY) {
|
|
|
|
deactivate_locked_super(s);
|
2010-07-26 14:03:58 +02:00
|
|
|
return ERR_PTR(-EBUSY);
|
2009-09-28 11:30:49 +02:00
|
|
|
}
|
2009-06-05 08:18:57 +02:00
|
|
|
sdp = s->s_fs_info;
|
2010-07-26 14:03:58 +02:00
|
|
|
return dget(sdp->sd_master_dir);
|
2006-01-16 17:50:04 +01:00
|
|
|
}
|
|
|
|
|
2006-03-02 22:33:41 +01:00
|
|
|
static void gfs2_kill_sb(struct super_block *sb)
|
2006-08-25 18:13:37 +02:00
|
|
|
{
|
|
|
|
struct gfs2_sbd *sdp = sb->s_fs_info;
|
2008-12-19 16:43:05 +01:00
|
|
|
|
|
|
|
if (sdp == NULL) {
|
|
|
|
kill_block_super(sb);
|
|
|
|
return;
|
2008-11-27 09:27:28 +01:00
|
|
|
}
|
2008-12-19 16:43:05 +01:00
|
|
|
|
|
|
|
gfs2_meta_syncfs(sdp);
|
|
|
|
dput(sdp->sd_root_dir);
|
|
|
|
dput(sdp->sd_master_dir);
|
|
|
|
sdp->sd_root_dir = NULL;
|
|
|
|
sdp->sd_master_dir = NULL;
|
2008-12-19 16:32:06 +01:00
|
|
|
shrink_dcache_sb(sb);
|
2008-08-08 14:45:13 +02:00
|
|
|
kill_block_super(sb);
|
2008-12-19 16:43:05 +01:00
|
|
|
gfs2_delete_debugfs_file(sdp);
|
GFS2: glock statistics gathering
The stats are divided into two sets: those relating to the
super block and those relating to an individual glock. The
super block stats are done on a per cpu basis in order to
try and reduce the overhead of gathering them. They are also
further divided by glock type.
In the case of both the super block and glock statistics,
the same information is gathered in each case. The super
block statistics are used to provide default values for
most of the glock statistics, so that newly created glocks
should have, as far as possible, a sensible starting point.
The statistics are divided into three pairs of mean and
variance, plus two counters. The mean/variance pairs are
smoothed exponential estimates and the algorithm used is
one which will be very familiar to those used to calculation
of round trip times in network code.
The three pairs of mean/variance measure the following
things:
1. DLM lock time (non-blocking requests)
2. DLM lock time (blocking requests)
3. Inter-request time (again to the DLM)
A non-blocking request is one which will complete right
away, whatever the state of the DLM lock in question. That
currently means any requests when (a) the current state of
the lock is exclusive (b) the requested state is either null
or unlocked or (c) the "try lock" flag is set. A blocking
request covers all the other lock requests.
There are two counters. The first is there primarily to show
how many lock requests have been made, and thus how much data
has gone into the mean/variance calculations. The other counter
is counting queueing of holders at the top layer of the glock
code. Hopefully that number will be a lot larger than the number
of dlm lock requests issued.
So why gather these statistics? There are several reasons
we'd like to get a better idea of these timings:
1. To be able to better set the glock "min hold time"
2. To spot performance issues more easily
3. To improve the algorithm for selecting resource groups for
allocation (to base it on lock wait time, rather than blindly
using a "try lock")
Due to the smoothing action of the updates, a step change in
some input quantity being sampled will only fully be taken
into account after 8 samples (or 4 for the variance) and this
needs to be carefully considered when interpreting the
results.
Knowing both the time it takes a lock request to complete and
the average time between lock requests for a glock means we
can compute the total percentage of the time for which the
node is able to use a glock vs. time that the rest of the
cluster has its share. That will be very useful when setting
the lock min hold time.
The other point to remember is that all times are in
nanoseconds. Great care has been taken to ensure that we
measure exactly the quantities that we want, as accurately
as possible. There are always inaccuracies in any
measuring system, but I hope this is as accurate as we
can reasonably make it.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2012-01-20 11:38:36 +01:00
|
|
|
free_percpu(sdp->sd_lkstats);
|
2008-12-19 16:43:05 +01:00
|
|
|
kfree(sdp);
|
2006-08-25 18:13:37 +02:00
|
|
|
}
|
|
|
|
|
2006-01-16 17:50:04 +01:00
|
|
|
struct file_system_type gfs2_fs_type = {
|
|
|
|
.name = "gfs2",
|
|
|
|
.fs_flags = FS_REQUIRES_DEV,
|
2010-07-26 14:03:58 +02:00
|
|
|
.mount = gfs2_mount,
|
2006-03-02 22:33:41 +01:00
|
|
|
.kill_sb = gfs2_kill_sb,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_system_type gfs2meta_fs_type = {
|
|
|
|
.name = "gfs2meta",
|
|
|
|
.fs_flags = FS_REQUIRES_DEV,
|
2010-07-26 14:03:58 +02:00
|
|
|
.mount = gfs2_mount_meta,
|
2006-01-16 17:50:04 +01:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|