Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F7632140
super.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
super.c
View Options
/******************************************************************************
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
** of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <asm/semaphore.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include "gfs.h"
#include "dio.h"
#include "file.h"
#include "format.h"
#include "glock.h"
#include "glops.h"
#include "inode.h"
#include "log.h"
#include "quota.h"
#include "recovery.h"
#include "rgrp.h"
#include "super.h"
#include "unlinked.h"
/**
* gfs_init_tune_data - Fill in the struct gfs_tune (sd_tune) in the struct gfs_sbd.
* @sdp: the filesystem
*
*/
void
gfs_init_tune_data(struct gfs_sbd *sdp)
{
struct gfs_tune *gt = &sdp->sd_tune;
gt->gt_tune_version = GFS_TUNE_VERSION;
gt->gt_ilimit1 = 100;
gt->gt_ilimit1_tries = 3;
gt->gt_ilimit1_min = 1;
gt->gt_ilimit2 = 500;
gt->gt_ilimit2_tries = 10;
gt->gt_ilimit2_min = 3;
gt->gt_demote_secs = 300;
gt->gt_incore_log_blocks = 1024;
gt->gt_jindex_refresh_secs = 60;
gt->gt_depend_secs = 60;
gt->gt_scand_secs = 5;
gt->gt_recoverd_secs = 60;
gt->gt_logd_secs = 1;
gt->gt_quotad_secs = 5;
gt->gt_inoded_secs = 15;
gt->gt_quota_simul_sync = 64;
gt->gt_quota_warn_period = 10;
gt->gt_atime_quantum = 3600;
gt->gt_quota_quantum = 60;
gt->gt_quota_scale_num = 1;
gt->gt_quota_scale_den = 1;
gt->gt_quota_enforce = 1;
gt->gt_quota_account = 1;
gt->gt_new_files_jdata = 0;
gt->gt_new_files_directio = 0;
gt->gt_max_atomic_write = 4 << 20;
gt->gt_max_readahead = 1 << 18;
gt->gt_lockdump_size = 131072;
gt->gt_stall_secs = 600;
gt->gt_complain_secs = 10;
gt->gt_reclaim_limit = 5000;
gt->gt_entries_per_readdir = 32;
gt->gt_prefetch_secs = 10;
gt->gt_statfs_slots = 64;
gt->gt_max_mhc = 10000;
gt->gt_greedy_default = HZ / 10;
gt->gt_greedy_quantum = HZ / 40;
gt->gt_greedy_max = HZ / 4;
}
/**
* gfs_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.
*/
int
gfs_check_sb(struct gfs_sbd *sdp, struct gfs_sb *sb, int silent)
{
unsigned int x;
if (sb->sb_header.mh_magic != GFS_MAGIC ||
sb->sb_header.mh_type != GFS_METATYPE_SB) {
if (!silent)
printk("GFS: not a GFS filesystem\n");
return -EINVAL;
}
/* If format numbers match exactly, we're done. */
if (sb->sb_fs_format == GFS_FORMAT_FS &&
sb->sb_multihost_format == GFS_FORMAT_MULTI)
return 0;
if (sb->sb_fs_format != GFS_FORMAT_FS) {
for (x = 0; gfs_old_fs_formats[x]; x++)
if (gfs_old_fs_formats[x] == sb->sb_fs_format)
break;
if (!gfs_old_fs_formats[x]) {
printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n",
GFS_FORMAT_FS, GFS_FORMAT_MULTI,
sb->sb_fs_format, sb->sb_multihost_format);
printk("GFS: I don't know how to upgrade this FS\n");
return -EINVAL;
}
}
if (sb->sb_multihost_format != GFS_FORMAT_MULTI) {
for (x = 0; gfs_old_multihost_formats[x]; x++)
if (gfs_old_multihost_formats[x] == sb->sb_multihost_format)
break;
if (!gfs_old_multihost_formats[x]) {
printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n",
GFS_FORMAT_FS, GFS_FORMAT_MULTI,
sb->sb_fs_format, sb->sb_multihost_format);
printk("GFS: I don't know how to upgrade this FS\n");
return -EINVAL;
}
}
if (!sdp->sd_args.ar_upgrade) {
printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n",
GFS_FORMAT_FS, GFS_FORMAT_MULTI,
sb->sb_fs_format, sb->sb_multihost_format);
printk("GFS: Use the \"upgrade\" mount option to upgrade the FS\n");
printk("GFS: See the manual for more details\n");
return -EINVAL;
}
return 0;
}
/**
* gfs_read_sb - Read super block
* @sdp: The GFS superblock
* @gl: the glock for the superblock (assumed to be held)
* @silent: Don't print message if mount fails
*
*/
int
gfs_read_sb(struct gfs_sbd *sdp, struct gfs_glock *gl, int silent)
{
struct buffer_head *bh;
uint32_t hash_blocks, ind_blocks, leaf_blocks;
uint32_t tmp_blocks;
unsigned int x;
int error;
error = gfs_dread(sdp, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift,
gl, DIO_FORCE | DIO_START | DIO_WAIT, &bh);
if (error) {
if (!silent)
printk("GFS: fsid=%s: can't read superblock\n",
sdp->sd_fsname);
return error;
}
GFS_ASSERT_SBD(sizeof(struct gfs_sb) <= bh->b_size, sdp,);
gfs_sb_in(&sdp->sd_sb, bh->b_data);
brelse(bh);
error = gfs_check_sb(sdp, &sdp->sd_sb, silent);
if (error)
return error;
sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
GFS_BASIC_BLOCK_SHIFT;
sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
sdp->sd_diptrs = (sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) /
sizeof(uint64_t);
sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - sizeof(struct gfs_indirect)) /
sizeof(uint64_t);
sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs_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(uint64_t);
/* Compute maximum reservation required to add a entry to a directory */
hash_blocks = DIV_RU(sizeof(uint64_t) * (1 << GFS_DIR_MAX_DEPTH),
sdp->sd_jbsize);
ind_blocks = 0;
for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
tmp_blocks = DIV_RU(tmp_blocks, sdp->sd_inptrs);
ind_blocks += tmp_blocks;
}
leaf_blocks = 2 + GFS_DIR_MAX_DEPTH;
sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode);
sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
for (x = 2;; x++) {
uint64_t space, d;
uint32_t 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;
GFS_ASSERT_SBD(sdp->sd_max_height <= GFS_MAX_META_HEIGHT, sdp,);
sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode);
sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
for (x = 2;; x++) {
uint64_t space, d;
uint32_t 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;
GFS_ASSERT_SBD(sdp->sd_max_jheight <= GFS_MAX_META_HEIGHT, sdp,);
return 0;
}
/**
* gfs_do_upgrade - upgrade a filesystem
* @sdp: The GFS superblock
*
*/
int
gfs_do_upgrade(struct gfs_sbd *sdp, struct gfs_glock *sb_gl)
{
struct gfs_holder ji_gh, t_gh, j_gh;
struct gfs_log_header lh;
struct buffer_head *bh;
unsigned int x;
int error;
/* If format numbers match exactly, we're done. */
if (sdp->sd_sb.sb_fs_format == GFS_FORMAT_FS &&
sdp->sd_sb.sb_multihost_format == GFS_FORMAT_MULTI) {
printk("GFS: fsid=%s: no upgrade necessary\n",
sdp->sd_fsname);
sdp->sd_args.ar_upgrade = FALSE;
return 0;
}
error = gfs_jindex_hold(sdp, &ji_gh);
if (error)
goto fail;
error = gfs_glock_nq_init(sdp->sd_trans_gl,
LM_ST_EXCLUSIVE, GL_NOCACHE,
&t_gh);
if (error)
goto fail_ji_relse;
if (test_bit(SDF_ROFS, &sdp->sd_flags)) {
printk("GFS: fsid=%s: can't upgrade: read-only FS\n",
sdp->sd_fsname);
error = -EROFS;
goto fail_gunlock_tr;
}
for (x = 0; x < sdp->sd_journals; x++) {
error = gfs_glock_nq_num(sdp,
sdp->sd_jindex[x].ji_addr,
&gfs_meta_glops, LM_ST_SHARED,
LM_FLAG_TRY | GL_NOCACHE, &j_gh);
switch (error) {
case 0:
break;
case GLR_TRYFAILED:
printk("GFS: fsid=%s: journal %u is busy\n",
sdp->sd_fsname, x);
error = -EBUSY;
default:
goto fail_gunlock_tr;
}
error = gfs_find_jhead(sdp, &sdp->sd_jindex[x],
j_gh.gh_gl, &lh);
gfs_glock_dq_uninit(&j_gh);
if (error)
goto fail_gunlock_tr;
if (!(lh.lh_flags & GFS_LOG_HEAD_UNMOUNT) || lh.lh_last_dump) {
printk("GFS: fsid=%s: journal %u is busy\n",
sdp->sd_fsname, x);
error = -EBUSY;
goto fail_gunlock_tr;
}
}
/* We don't need to journal this change because we're changing
only one sector of one block. We definitely don't want to have
the journaling code running at this point. */
error = gfs_dread(sdp, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift, sb_gl,
DIO_START | DIO_WAIT, &bh);
if (error)
goto fail_gunlock_tr;
gfs_sb_in(&sdp->sd_sb, bh->b_data);
error = gfs_check_sb(sdp, &sdp->sd_sb, FALSE);
GFS_ASSERT_SBD(!error, sdp,);
sdp->sd_sb.sb_fs_format = GFS_FORMAT_FS;
sdp->sd_sb.sb_multihost_format = GFS_FORMAT_MULTI;
gfs_sb_out(&sdp->sd_sb, bh->b_data);
set_bit(GLF_DIRTY, &sb_gl->gl_flags);
error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT);
brelse(bh);
gfs_glock_dq_uninit(&t_gh);
gfs_glock_dq_uninit(&ji_gh);
if (!error) {
printk("GFS: fsid=%s: upgrade successful\n",
sdp->sd_fsname);
sdp->sd_args.ar_upgrade = FALSE;
}
return error;
fail_gunlock_tr:
gfs_glock_dq_uninit(&t_gh);
fail_ji_relse:
gfs_glock_dq_uninit(&ji_gh);
fail:
if (error == -EBUSY)
printk("GFS: fsid=%s: can't upgrade: the FS is still busy or contains dirty journals\n",
sdp->sd_fsname);
else
printk("GFS: fsid=%s: can't upgrade: %d\n",
sdp->sd_fsname, error);
return error;
}
/**
* clear_journalsi - Clear all the journal index information (without locking)
* @sdp: The GFS superblock
*
*/
static void
clear_journalsi(struct gfs_sbd *sdp)
{
if (sdp->sd_jindex) {
kfree(sdp->sd_jindex);
sdp->sd_jindex = NULL;
}
sdp->sd_journals = 0;
}
/**
* gfs_clear_journals - Clear all the journal index information
* @sdp: The GFS superblock
*
*/
void
gfs_clear_journals(struct gfs_sbd *sdp)
{
down(&sdp->sd_jindex_lock);
clear_journalsi(sdp);
up(&sdp->sd_jindex_lock);
}
/**
* gfs_ji_update - Update the journal index information
* @ip: The journal index inode
*
* Returns: errno
*/
static int
gfs_ji_update(struct gfs_inode *ip)
{
struct gfs_sbd *sdp = ip->i_sbd;
char buf[sizeof(struct gfs_jindex)];
unsigned int j;
int error;
GFS_ASSERT_SBD(!do_mod(ip->i_di.di_size, sizeof(struct gfs_jindex)),
sdp,);
clear_journalsi(sdp);
sdp->sd_jindex = kmalloc(ip->i_di.di_size, GFP_KERNEL);
if (!sdp->sd_jindex)
return -ENOMEM;
memset(sdp->sd_jindex, 0, ip->i_di.di_size);
for (j = 0;; j++) {
error = gfs_internal_read(ip, buf,
j * sizeof(struct gfs_jindex),
sizeof(struct gfs_jindex));
if (!error)
break;
if (error != sizeof(struct gfs_jindex)) {
if (error > 0)
error = -EIO;
goto fail;
}
gfs_jindex_in(sdp->sd_jindex + j, buf);
}
GFS_ASSERT_SBD(j * sizeof(struct gfs_jindex) == ip->i_di.di_size,
sdp,);
sdp->sd_journals = j;
sdp->sd_jiinode_vn = ip->i_gl->gl_vn;
return 0;
fail:
clear_journalsi(sdp);
return error;
}
/**
* gfs_jindex_hold - Grab a lock on the jindex
* @sdp: The GFS superblock
* @ji_gh: the holder for the jindex glock
*
* This makes sure that we're using the latest copy of the journal index
* special file (this describes all of the journals for this filesystem),
* which might have been updated if someone added journals
* (via gfs_jadd utility).
*
* This is very similar to the gfs_rindex_hold() function, except that
* in general we hold the jindex lock for longer periods of time and
* we grab it far less frequently (in general) then the rgrp lock.
*
* Returns: errno
*/
int
gfs_jindex_hold(struct gfs_sbd *sdp, struct gfs_holder *ji_gh)
{
struct gfs_inode *ip = sdp->sd_jiinode;
struct gfs_glock *gl = ip->i_gl;
int error;
error = gfs_glock_nq_init(gl, LM_ST_SHARED, 0, ji_gh);
if (error)
return error;
/* Read new copy from disk if we don't have the latest */
if (sdp->sd_jiinode_vn != gl->gl_vn) {
down(&sdp->sd_jindex_lock);
if (sdp->sd_jiinode_vn != gl->gl_vn)
error = gfs_ji_update(ip);
up(&sdp->sd_jindex_lock);
}
if (error)
gfs_glock_dq_uninit(ji_gh);
return error;
}
/**
* gfs_get_jiinode - Read-in the special (hidden) journal index inode
* @sdp: The GFS superblock
*
* Returns: errno
*
* This reads-in just the dinode, not the special file contents that describe
* the journals themselves (see gfs_jindex_hold()).
*/
int
gfs_get_jiinode(struct gfs_sbd *sdp)
{
struct gfs_holder ji_gh;
int error;
error = gfs_glock_nq_num(sdp,
sdp->sd_sb.sb_jindex_di.no_formal_ino,
&gfs_inode_glops,
LM_ST_SHARED, GL_LOCAL_EXCL,
&ji_gh);
if (error)
return error;
error = gfs_inode_get(ji_gh.gh_gl, &sdp->sd_sb.sb_jindex_di,
CREATE, &sdp->sd_jiinode);
if (!error) {
sdp->sd_jiinode_vn = ji_gh.gh_gl->gl_vn - 1;
set_bit(GLF_STICKY, &ji_gh.gh_gl->gl_flags);
}
gfs_glock_dq_uninit(&ji_gh);
return error;
}
/**
* gfs_get_riinode - Read in the special (hidden) resource group index inode
* @sdp: The GFS superblock
*
* Returns: errno
*
* This reads-in just the dinode, not the special file contents that describe
* the resource groups themselves (see gfs_rindex_hold()).
*/
int
gfs_get_riinode(struct gfs_sbd *sdp)
{
struct gfs_holder ri_gh;
int error;
error = gfs_glock_nq_num(sdp,
sdp->sd_sb.sb_rindex_di.no_formal_ino,
&gfs_inode_glops,
LM_ST_SHARED, GL_LOCAL_EXCL,
&ri_gh);
if (error)
return error;
error = gfs_inode_get(ri_gh.gh_gl, &sdp->sd_sb.sb_rindex_di,
CREATE, &sdp->sd_riinode);
if (!error) {
sdp->sd_riinode_vn = ri_gh.gh_gl->gl_vn - 1;
set_bit(GLF_STICKY, &ri_gh.gh_gl->gl_flags);
}
gfs_glock_dq_uninit(&ri_gh);
return error;
}
/**
* gfs_get_rootinode - Read in the filesystem's root inode
* @sdp: The GFS superblock
*
* Returns: errno
*/
int
gfs_get_rootinode(struct gfs_sbd *sdp)
{
struct gfs_holder i_gh;
int error;
error = gfs_glock_nq_num(sdp,
sdp->sd_sb.sb_root_di.no_formal_ino,
&gfs_inode_glops,
LM_ST_SHARED, GL_LOCAL_EXCL,
&i_gh);
if (error)
return error;
error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_root_di,
CREATE, &sdp->sd_rooti);
gfs_glock_dq_uninit(&i_gh);
return error;
}
/**
* gfs_get_qinode - Read in the special (hidden) quota inode
* @sdp: The GFS superblock
*
* If one is not on-disk already, create a new one.
* Does not read in file contents, just the dinode.
*
* Returns: errno
*/
int
gfs_get_qinode(struct gfs_sbd *sdp)
{
struct gfs_holder i_gh;
int error;
/* Create, if not on-disk already */
if (!sdp->sd_sb.sb_quota_di.no_formal_ino) {
error = gfs_alloc_qinode(sdp);
if (error)
return error;
}
error = gfs_glock_nq_num(sdp,
sdp->sd_sb.sb_quota_di.no_formal_ino,
&gfs_inode_glops,
LM_ST_SHARED, GL_LOCAL_EXCL,
&i_gh);
if (error)
return error;
error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_quota_di,
CREATE, &sdp->sd_qinode);
gfs_glock_dq_uninit(&i_gh);
return error;
}
/**
* gfs_get_linode - Read in the special (hidden) license inode
* @sdp: The GFS superblock
*
* If one is not on-disk already, create a new one.
* Does not read in file contents, just the dinode.
*
* Returns: errno
*/
int
gfs_get_linode(struct gfs_sbd *sdp)
{
struct gfs_holder i_gh;
int error;
/* Create, if not on-disk already */
if (!sdp->sd_sb.sb_license_di.no_formal_ino) {
error = gfs_alloc_linode(sdp);
if (error)
return error;
}
error = gfs_glock_nq_num(sdp,
sdp->sd_sb.sb_license_di.no_formal_ino,
&gfs_inode_glops,
LM_ST_SHARED, GL_LOCAL_EXCL,
&i_gh);
if (error)
return error;
error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_license_di,
CREATE, &sdp->sd_linode);
gfs_glock_dq_uninit(&i_gh);
return error;
}
/**
* gfs_make_fs_rw - Turn a Read-Only FS into a Read-Write one
* @sdp: the filesystem
*
* Returns: errno
*/
int
gfs_make_fs_rw(struct gfs_sbd *sdp)
{
struct gfs_glock *j_gl = sdp->sd_journal_gh.gh_gl;
struct gfs_holder t_gh;
struct gfs_log_header head;
int error;
error = gfs_glock_nq_init(sdp->sd_trans_gl,
LM_ST_SHARED,
GL_LOCAL_EXCL | GL_EXACT,
&t_gh);
if (error)
return error;
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
error = gfs_find_jhead(sdp, &sdp->sd_jdesc, j_gl, &head);
if (error)
goto fail;
GFS_ASSERT_SBD(head.lh_flags & GFS_LOG_HEAD_UNMOUNT, sdp,);
/* Initialize some head of the log stuff */
sdp->sd_sequence = head.lh_sequence;
sdp->sd_log_head = head.lh_first + 1;
error = gfs_recover_dump(sdp);
if (error)
goto fail;
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
clear_bit(SDF_ROFS, &sdp->sd_flags);
set_bit(GLF_DIRTY, &j_gl->gl_flags);
gfs_log_dump(sdp, TRUE);
gfs_glock_dq_uninit(&t_gh);
return 0;
fail:
t_gh.gh_flags |= GL_NOCACHE;
gfs_glock_dq_uninit(&t_gh);
return error;
}
/**
* gfs_make_fs_ro - Turn a Read-Write FS into a Read-Only one
* @sdp: the filesystem
*
* Returns: errno
*/
int
gfs_make_fs_ro(struct gfs_sbd *sdp)
{
struct gfs_holder t_gh;
int error;
error = gfs_glock_nq_init(sdp->sd_trans_gl,
LM_ST_SHARED,
GL_LOCAL_EXCL | GL_EXACT | GL_NOCACHE,
&t_gh);
if (error)
return error;
gfs_sync_meta(sdp);
gfs_log_dump(sdp, TRUE);
error = gfs_log_shutdown(sdp);
if (error)
gfs_io_error(sdp);
set_bit(SDF_ROFS, &sdp->sd_flags);
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
gfs_glock_dq_uninit(&t_gh);
gfs_unlinked_cleanup(sdp);
gfs_quota_cleanup(sdp);
return error;
}
/**
* stat_gfs_fill - fill in the usage for a given RG
* @rgd: the RG
* @usage: the usage structure
*
* Returns: 0 on success, -ESTALE if the LVB is invalid
*/
static int
stat_gfs_fill(struct gfs_rgrpd *rgd, struct gfs_usage *usage)
{
struct gfs_rgrp_lvb *rb = (struct gfs_rgrp_lvb *)rgd->rd_gl->gl_lvb;
if (test_bit(GLF_LVB_INVALID, &rgd->rd_gl->gl_flags) ||
gfs32_to_cpu(rb->rb_magic) != GFS_MAGIC)
return -ESTALE;
usage->gu_total_blocks += rgd->rd_ri.ri_data;
usage->gu_free += gfs32_to_cpu(rb->rb_free);
usage->gu_used_dinode += gfs32_to_cpu(rb->rb_useddi);
usage->gu_free_dinode += gfs32_to_cpu(rb->rb_freedi);
usage->gu_used_meta += gfs32_to_cpu(rb->rb_usedmeta);
usage->gu_free_meta += gfs32_to_cpu(rb->rb_freemeta);
return 0;
}
/**
* stat_gfs_async - Stat a filesystem using asynchronous locking
* @sdp: the filesystem
* @usage: the usage info that will be returned
* @interruptible: TRUE if we should look for signals.
*
* Any error (other than a signal) will cause this routine to fall back
* to the synchronous version.
*
* FIXME: This really shouldn't busy wait like this.
*
* Returns: errno
*/
static int
stat_gfs_async(struct gfs_sbd *sdp, struct gfs_usage *usage, int interruptible)
{
struct gfs_rgrpd *rgd_next = gfs_rgrpd_get_first(sdp);
struct gfs_holder *gha, *gh;
unsigned int slots = sdp->sd_tune.gt_statfs_slots;
unsigned int x;
int done;
int error = 0, err;
memset(usage, 0, sizeof(struct gfs_usage));
usage->gu_block_size = sdp->sd_sb.sb_bsize;
gha = kmalloc(slots * sizeof(struct gfs_holder), GFP_KERNEL);
if (!gha)
return -ENOMEM;
memset(gha, 0, slots * sizeof(struct gfs_holder));
for (;;) {
done = TRUE;
for (x = 0; x < slots; x++) {
gh = gha + x;
if (gh->gh_gl && gfs_glock_poll(gh)) {
err = gfs_glock_wait(gh);
if (err) {
gfs_holder_uninit(gh);
error = err;
} else {
error = stat_gfs_fill(gl2rgd(gh->gh_gl),
usage);
gfs_glock_dq_uninit(gh);
}
}
if (gh->gh_gl)
done = FALSE;
else if (rgd_next && !error) {
gfs_glock_nq_init(rgd_next->rd_gl,
LM_ST_SHARED,
GL_LOCAL_EXCL | GL_SKIP | GL_ASYNC,
gh);
rgd_next = gfs_rgrpd_get_next(rgd_next);
done = FALSE;
}
if (interruptible && signal_pending(current))
error = -ERESTARTSYS;
}
if (done)
break;
yield();
}
kfree(gha);
return error;
}
/**
* stat_gfs_sync - Stat a filesystem using synchronous locking
* @sdp: the filesystem
* @usage: the usage info that will be returned
* @interruptible: TRUE if we should look for signals.
*
* Returns: errno
*/
static int
stat_gfs_sync(struct gfs_sbd *sdp, struct gfs_usage *usage, int interruptible)
{
struct gfs_holder rgd_gh;
struct gfs_rgrpd *rgd;
int error;
memset(usage, 0, sizeof(struct gfs_usage));
usage->gu_block_size = sdp->sd_sb.sb_bsize;
for (rgd = gfs_rgrpd_get_first(sdp);
rgd;
rgd = gfs_rgrpd_get_next(rgd)) {
for (;;) {
error = gfs_glock_nq_init(rgd->rd_gl,
LM_ST_SHARED,
GL_LOCAL_EXCL | GL_SKIP,
&rgd_gh);
if (error)
return error;
error = stat_gfs_fill(rgd, usage);
gfs_glock_dq_uninit(&rgd_gh);
if (!error)
break;
error = gfs_rgrp_lvb_init(rgd);
if (error)
return error;
}
if (interruptible && signal_pending(current))
return -ERESTARTSYS;
}
return 0;
}
/**
* gfs_stat_gfs - Do a statfs
* @sdp: the filesystem
* @usage: the usage structure
* @interruptible: Stop if there is a signal pending
*
* Returns: errno
*/
int
gfs_stat_gfs(struct gfs_sbd *sdp, struct gfs_usage *usage, int interruptible)
{
struct gfs_holder ri_gh;
int error;
error = gfs_rindex_hold(sdp, &ri_gh);
if (error)
return error;
error = stat_gfs_async(sdp, usage, interruptible);
if (error == -ESTALE)
error = stat_gfs_sync(sdp, usage, interruptible);
gfs_glock_dq_uninit(&ri_gh);
return error;
}
/**
* gfs_lock_fs_check_clean - Stop all writes to the FS and check that all journals are clean
* @sdp: the file system
* @state: the state to put the transaction lock into
* @t_gh: the hold on the transaction lock
*
* Returns: errno
*/
int
gfs_lock_fs_check_clean(struct gfs_sbd *sdp, unsigned int state,
struct gfs_holder *t_gh)
{
struct gfs_holder ji_gh, cl_gh;
struct gfs_log_header lh;
unsigned int x;
int error;
error = gfs_jindex_hold(sdp, &ji_gh);
if (error)
return error;
error = gfs_glock_nq_num(sdp,
GFS_CRAP_LOCK, &gfs_meta_glops,
LM_ST_SHARED, GL_NOCACHE,
&cl_gh);
if (error)
goto fail;
error = gfs_glock_nq_init(sdp->sd_trans_gl, state,
LM_FLAG_PRIORITY | GL_EXACT | GL_NOCACHE,
t_gh);
if (error)
goto fail_gunlock_craplock;
for (x = 0; x < sdp->sd_journals; x++) {
error = gfs_find_jhead(sdp, &sdp->sd_jindex[x],
cl_gh.gh_gl, &lh);
if (error)
goto fail_gunlock_trans;
if (!(lh.lh_flags & GFS_LOG_HEAD_UNMOUNT)) {
error = -EBUSY;
goto fail_gunlock_trans;
}
}
gfs_glock_dq_uninit(&cl_gh);
gfs_glock_dq_uninit(&ji_gh);
return 0;
fail_gunlock_trans:
gfs_glock_dq_uninit(t_gh);
fail_gunlock_craplock:
gfs_glock_dq_uninit(&cl_gh);
fail:
gfs_glock_dq_uninit(&ji_gh);
return error;
}
/**
* gfs_freeze_fs - freezes the file system
* @sdp: the file system
*
* This function flushes data and meta data for all machines by
* aquiring the transaction log exclusively. All journals are
* ensured to be in a clean state as well.
*
* Returns: errno
*/
int
gfs_freeze_fs(struct gfs_sbd *sdp)
{
int error = 0;
down(&sdp->sd_freeze_lock);
if (!sdp->sd_freeze_count++) {
error = gfs_lock_fs_check_clean(sdp, LM_ST_DEFERRED,
&sdp->sd_freeze_gh);
if (error)
sdp->sd_freeze_count--;
else
sdp->sd_freeze_gh.gh_owner = NULL;
}
up(&sdp->sd_freeze_lock);
return error;
}
/**
* gfs_unfreeze_fs - unfreezes the file system
* @sdp: the file system
*
* This function allows the file system to proceed by unlocking
* the exclusively held transaction lock. Other GFS nodes are
* now free to acquire the lock shared and go on with their lives.
*
*/
void
gfs_unfreeze_fs(struct gfs_sbd *sdp)
{
down(&sdp->sd_freeze_lock);
if (sdp->sd_freeze_count && !--sdp->sd_freeze_count)
gfs_glock_dq_uninit(&sdp->sd_freeze_gh);
up(&sdp->sd_freeze_lock);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Oct 16, 3:17 PM (20 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2522284
Default Alt Text
super.c (23 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment