1b3b94faaSDavid Teigland /* 2b3b94faaSDavid Teigland * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 33a8a9a10SSteven Whitehouse * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 4b3b94faaSDavid Teigland * 5b3b94faaSDavid Teigland * This copyrighted material is made available to anyone wishing to use, 6b3b94faaSDavid Teigland * modify, copy, or redistribute it subject to the terms and conditions 7e9fc2aa0SSteven Whitehouse * of the GNU General Public License version 2. 8b3b94faaSDavid Teigland */ 9b3b94faaSDavid Teigland 10b3b94faaSDavid Teigland #include <linux/sched.h> 11b3b94faaSDavid Teigland #include <linux/slab.h> 12b3b94faaSDavid Teigland #include <linux/spinlock.h> 13b3b94faaSDavid Teigland #include <linux/completion.h> 14b3b94faaSDavid Teigland #include <linux/buffer_head.h> 1571b86f56SSteven Whitehouse #include <linux/crc32.h> 165c676f6dSSteven Whitehouse #include <linux/gfs2_ondisk.h> 17f45b7dddSSteven Whitehouse #include <linux/bio.h> 18b3b94faaSDavid Teigland 19b3b94faaSDavid Teigland #include "gfs2.h" 205c676f6dSSteven Whitehouse #include "lm_interface.h" 215c676f6dSSteven Whitehouse #include "incore.h" 22b3b94faaSDavid Teigland #include "bmap.h" 23b3b94faaSDavid Teigland #include "dir.h" 24b3b94faaSDavid Teigland #include "glock.h" 25b3b94faaSDavid Teigland #include "glops.h" 26b3b94faaSDavid Teigland #include "inode.h" 27b3b94faaSDavid Teigland #include "log.h" 28b3b94faaSDavid Teigland #include "meta_io.h" 29b3b94faaSDavid Teigland #include "quota.h" 30b3b94faaSDavid Teigland #include "recovery.h" 31b3b94faaSDavid Teigland #include "rgrp.h" 32b3b94faaSDavid Teigland #include "super.h" 33b3b94faaSDavid Teigland #include "trans.h" 345c676f6dSSteven Whitehouse #include "util.h" 35b3b94faaSDavid Teigland 3675d3b817SSteven Whitehouse static const uint32_t gfs2_old_fs_formats[] = { 3775d3b817SSteven Whitehouse 0 3875d3b817SSteven Whitehouse }; 3975d3b817SSteven Whitehouse 4075d3b817SSteven Whitehouse static const uint32_t gfs2_old_multihost_formats[] = { 4175d3b817SSteven Whitehouse 0 4275d3b817SSteven Whitehouse }; 4375d3b817SSteven Whitehouse 44b3b94faaSDavid Teigland /** 45b3b94faaSDavid Teigland * gfs2_tune_init - Fill a gfs2_tune structure with default values 46b3b94faaSDavid Teigland * @gt: tune 47b3b94faaSDavid Teigland * 48b3b94faaSDavid Teigland */ 49b3b94faaSDavid Teigland 50b3b94faaSDavid Teigland void gfs2_tune_init(struct gfs2_tune *gt) 51b3b94faaSDavid Teigland { 52b3b94faaSDavid Teigland spin_lock_init(>->gt_spin); 53b3b94faaSDavid Teigland 54b3b94faaSDavid Teigland gt->gt_ilimit = 100; 55b3b94faaSDavid Teigland gt->gt_ilimit_tries = 3; 56b3b94faaSDavid Teigland gt->gt_ilimit_min = 1; 57b3b94faaSDavid Teigland gt->gt_demote_secs = 300; 58b3b94faaSDavid Teigland gt->gt_incore_log_blocks = 1024; 59b3b94faaSDavid Teigland gt->gt_log_flush_secs = 60; 60b3b94faaSDavid Teigland gt->gt_jindex_refresh_secs = 60; 61b3b94faaSDavid Teigland gt->gt_scand_secs = 15; 62b3b94faaSDavid Teigland gt->gt_recoverd_secs = 60; 63b3b94faaSDavid Teigland gt->gt_logd_secs = 1; 64b3b94faaSDavid Teigland gt->gt_quotad_secs = 5; 65b3b94faaSDavid Teigland gt->gt_quota_simul_sync = 64; 66b3b94faaSDavid Teigland gt->gt_quota_warn_period = 10; 67b3b94faaSDavid Teigland gt->gt_quota_scale_num = 1; 68b3b94faaSDavid Teigland gt->gt_quota_scale_den = 1; 69b3b94faaSDavid Teigland gt->gt_quota_cache_secs = 300; 70b3b94faaSDavid Teigland gt->gt_quota_quantum = 60; 71b3b94faaSDavid Teigland gt->gt_atime_quantum = 3600; 72b3b94faaSDavid Teigland gt->gt_new_files_jdata = 0; 73b3b94faaSDavid Teigland gt->gt_new_files_directio = 0; 74b3b94faaSDavid Teigland gt->gt_max_atomic_write = 4 << 20; 75b3b94faaSDavid Teigland gt->gt_max_readahead = 1 << 18; 76b3b94faaSDavid Teigland gt->gt_lockdump_size = 131072; 77b3b94faaSDavid Teigland gt->gt_stall_secs = 600; 78b3b94faaSDavid Teigland gt->gt_complain_secs = 10; 79b3b94faaSDavid Teigland gt->gt_reclaim_limit = 5000; 80b3b94faaSDavid Teigland gt->gt_entries_per_readdir = 32; 81b3b94faaSDavid Teigland gt->gt_prefetch_secs = 10; 82b3b94faaSDavid Teigland gt->gt_greedy_default = HZ / 10; 83b3b94faaSDavid Teigland gt->gt_greedy_quantum = HZ / 40; 84b3b94faaSDavid Teigland gt->gt_greedy_max = HZ / 4; 85b3b94faaSDavid Teigland gt->gt_statfs_quantum = 30; 86b3b94faaSDavid Teigland gt->gt_statfs_slow = 0; 87b3b94faaSDavid Teigland } 88b3b94faaSDavid Teigland 89b3b94faaSDavid Teigland /** 90b3b94faaSDavid Teigland * gfs2_check_sb - Check superblock 91b3b94faaSDavid Teigland * @sdp: the filesystem 92b3b94faaSDavid Teigland * @sb: The superblock 93b3b94faaSDavid Teigland * @silent: Don't print a message if the check fails 94b3b94faaSDavid Teigland * 95b3b94faaSDavid Teigland * Checks the version code of the FS is one that we understand how to 96b3b94faaSDavid Teigland * read and that the sizes of the various on-disk structures have not 97b3b94faaSDavid Teigland * changed. 98b3b94faaSDavid Teigland */ 99b3b94faaSDavid Teigland 100b3b94faaSDavid Teigland int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) 101b3b94faaSDavid Teigland { 102b3b94faaSDavid Teigland unsigned int x; 103b3b94faaSDavid Teigland 104b3b94faaSDavid Teigland if (sb->sb_header.mh_magic != GFS2_MAGIC || 105b3b94faaSDavid Teigland sb->sb_header.mh_type != GFS2_METATYPE_SB) { 106b3b94faaSDavid Teigland if (!silent) 107d92a8d48SSteven Whitehouse printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n"); 108b3b94faaSDavid Teigland return -EINVAL; 109b3b94faaSDavid Teigland } 110b3b94faaSDavid Teigland 111b3b94faaSDavid Teigland /* If format numbers match exactly, we're done. */ 112b3b94faaSDavid Teigland 113b3b94faaSDavid Teigland if (sb->sb_fs_format == GFS2_FORMAT_FS && 114b3b94faaSDavid Teigland sb->sb_multihost_format == GFS2_FORMAT_MULTI) 115b3b94faaSDavid Teigland return 0; 116b3b94faaSDavid Teigland 117b3b94faaSDavid Teigland if (sb->sb_fs_format != GFS2_FORMAT_FS) { 118b3b94faaSDavid Teigland for (x = 0; gfs2_old_fs_formats[x]; x++) 119b3b94faaSDavid Teigland if (gfs2_old_fs_formats[x] == sb->sb_fs_format) 120b3b94faaSDavid Teigland break; 121b3b94faaSDavid Teigland 122b3b94faaSDavid Teigland if (!gfs2_old_fs_formats[x]) { 123568f4c96SSteven Whitehouse printk(KERN_WARNING 124568f4c96SSteven Whitehouse "GFS2: code version (%u, %u) is incompatible " 125b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 126b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 127b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 128568f4c96SSteven Whitehouse printk(KERN_WARNING 129568f4c96SSteven Whitehouse "GFS2: I don't know how to upgrade this FS\n"); 130b3b94faaSDavid Teigland return -EINVAL; 131b3b94faaSDavid Teigland } 132b3b94faaSDavid Teigland } 133b3b94faaSDavid Teigland 134b3b94faaSDavid Teigland if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) { 135b3b94faaSDavid Teigland for (x = 0; gfs2_old_multihost_formats[x]; x++) 136568f4c96SSteven Whitehouse if (gfs2_old_multihost_formats[x] == 137568f4c96SSteven Whitehouse sb->sb_multihost_format) 138b3b94faaSDavid Teigland break; 139b3b94faaSDavid Teigland 140b3b94faaSDavid Teigland if (!gfs2_old_multihost_formats[x]) { 141568f4c96SSteven Whitehouse printk(KERN_WARNING 142568f4c96SSteven Whitehouse "GFS2: code version (%u, %u) is incompatible " 143b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 144b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 145b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 146568f4c96SSteven Whitehouse printk(KERN_WARNING 147568f4c96SSteven Whitehouse "GFS2: I don't know how to upgrade this FS\n"); 148b3b94faaSDavid Teigland return -EINVAL; 149b3b94faaSDavid Teigland } 150b3b94faaSDavid Teigland } 151b3b94faaSDavid Teigland 152b3b94faaSDavid Teigland if (!sdp->sd_args.ar_upgrade) { 153568f4c96SSteven Whitehouse printk(KERN_WARNING 154568f4c96SSteven Whitehouse "GFS2: code version (%u, %u) is incompatible " 155b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 156b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 157b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 158568f4c96SSteven Whitehouse printk(KERN_INFO 159568f4c96SSteven Whitehouse "GFS2: Use the \"upgrade\" mount option to upgrade " 160b3b94faaSDavid Teigland "the FS\n"); 161d92a8d48SSteven Whitehouse printk(KERN_INFO "GFS2: See the manual for more details\n"); 162b3b94faaSDavid Teigland return -EINVAL; 163b3b94faaSDavid Teigland } 164b3b94faaSDavid Teigland 165b3b94faaSDavid Teigland return 0; 166b3b94faaSDavid Teigland } 167b3b94faaSDavid Teigland 168f45b7dddSSteven Whitehouse 169f45b7dddSSteven Whitehouse static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) 170f45b7dddSSteven Whitehouse { 171f45b7dddSSteven Whitehouse struct page *page = bio->bi_private; 172f45b7dddSSteven Whitehouse if (bio->bi_size) 173f45b7dddSSteven Whitehouse return 1; 174f45b7dddSSteven Whitehouse 175f45b7dddSSteven Whitehouse if (!error) 176f45b7dddSSteven Whitehouse SetPageUptodate(page); 1772b98a54fSSteven Whitehouse else 1782b98a54fSSteven Whitehouse printk(KERN_WARNING "gfs2: error %d reading superblock\n", error); 179f45b7dddSSteven Whitehouse unlock_page(page); 180f45b7dddSSteven Whitehouse return 0; 181f45b7dddSSteven Whitehouse } 182f45b7dddSSteven Whitehouse 183f45b7dddSSteven Whitehouse static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) 184f45b7dddSSteven Whitehouse { 185f45b7dddSSteven Whitehouse struct page *page; 186f45b7dddSSteven Whitehouse struct bio *bio; 187f45b7dddSSteven Whitehouse 188f45b7dddSSteven Whitehouse page = alloc_page(GFP_KERNEL); 189f45b7dddSSteven Whitehouse if (unlikely(!page)) 190f45b7dddSSteven Whitehouse return NULL; 191f45b7dddSSteven Whitehouse 192f45b7dddSSteven Whitehouse ClearPageUptodate(page); 193f45b7dddSSteven Whitehouse ClearPageDirty(page); 194f45b7dddSSteven Whitehouse lock_page(page); 195f45b7dddSSteven Whitehouse 196f45b7dddSSteven Whitehouse bio = bio_alloc(GFP_KERNEL, 1); 197f45b7dddSSteven Whitehouse if (unlikely(!bio)) { 198f45b7dddSSteven Whitehouse __free_page(page); 199f45b7dddSSteven Whitehouse return NULL; 200f45b7dddSSteven Whitehouse } 201f45b7dddSSteven Whitehouse 202f45b7dddSSteven Whitehouse bio->bi_sector = sector; 203f45b7dddSSteven Whitehouse bio->bi_bdev = sb->s_bdev; 204f45b7dddSSteven Whitehouse bio_add_page(bio, page, PAGE_SIZE, 0); 205f45b7dddSSteven Whitehouse 206f45b7dddSSteven Whitehouse bio->bi_end_io = end_bio_io_page; 207f45b7dddSSteven Whitehouse bio->bi_private = page; 2082b98a54fSSteven Whitehouse submit_bio(READ_SYNC, bio); 209f45b7dddSSteven Whitehouse wait_on_page_locked(page); 210f45b7dddSSteven Whitehouse bio_put(bio); 211f45b7dddSSteven Whitehouse if (!PageUptodate(page)) { 212f45b7dddSSteven Whitehouse __free_page(page); 213f45b7dddSSteven Whitehouse return NULL; 214f45b7dddSSteven Whitehouse } 215f45b7dddSSteven Whitehouse return page; 216f45b7dddSSteven Whitehouse } 217f45b7dddSSteven Whitehouse 218b3b94faaSDavid Teigland /** 219b3b94faaSDavid Teigland * gfs2_read_sb - Read super block 220b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 221b3b94faaSDavid Teigland * @gl: the glock for the superblock (assumed to be held) 222b3b94faaSDavid Teigland * @silent: Don't print message if mount fails 223b3b94faaSDavid Teigland * 224b3b94faaSDavid Teigland */ 225b3b94faaSDavid Teigland 226b3b94faaSDavid Teigland int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) 227b3b94faaSDavid Teigland { 228b3b94faaSDavid Teigland uint32_t hash_blocks, ind_blocks, leaf_blocks; 229b3b94faaSDavid Teigland uint32_t tmp_blocks; 230b3b94faaSDavid Teigland unsigned int x; 231b3b94faaSDavid Teigland int error; 232f45b7dddSSteven Whitehouse struct page *page; 233f45b7dddSSteven Whitehouse char *sb; 234b3b94faaSDavid Teigland 235f45b7dddSSteven Whitehouse page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); 236f45b7dddSSteven Whitehouse if (!page) { 237b3b94faaSDavid Teigland if (!silent) 238b3b94faaSDavid Teigland fs_err(sdp, "can't read superblock\n"); 239f45b7dddSSteven Whitehouse return -EIO; 240b3b94faaSDavid Teigland } 241f45b7dddSSteven Whitehouse sb = kmap(page); 242f45b7dddSSteven Whitehouse gfs2_sb_in(&sdp->sd_sb, sb); 243f45b7dddSSteven Whitehouse kunmap(page); 244f45b7dddSSteven Whitehouse __free_page(page); 245b3b94faaSDavid Teigland 246b3b94faaSDavid Teigland error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); 247b3b94faaSDavid Teigland if (error) 248b3b94faaSDavid Teigland return error; 249b3b94faaSDavid Teigland 250b3b94faaSDavid Teigland sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - 251b3b94faaSDavid Teigland GFS2_BASIC_BLOCK_SHIFT; 252b3b94faaSDavid Teigland sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; 253b3b94faaSDavid Teigland sdp->sd_diptrs = (sdp->sd_sb.sb_bsize - 254b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)) / sizeof(uint64_t); 255b3b94faaSDavid Teigland sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - 256b3b94faaSDavid Teigland sizeof(struct gfs2_meta_header)) / sizeof(uint64_t); 257b3b94faaSDavid Teigland sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); 258b3b94faaSDavid Teigland sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2; 259b3b94faaSDavid Teigland sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1; 260b3b94faaSDavid Teigland sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); 261b3b94faaSDavid Teigland sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize - 262b3b94faaSDavid Teigland sizeof(struct gfs2_meta_header)) / 263b3b94faaSDavid Teigland sizeof(struct gfs2_quota_change); 264b3b94faaSDavid Teigland 265b3b94faaSDavid Teigland /* Compute maximum reservation required to add a entry to a directory */ 266b3b94faaSDavid Teigland 2675c676f6dSSteven Whitehouse hash_blocks = DIV_ROUND_UP(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), 268b3b94faaSDavid Teigland sdp->sd_jbsize); 269b3b94faaSDavid Teigland 270b3b94faaSDavid Teigland ind_blocks = 0; 271b3b94faaSDavid Teigland for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) { 2725c676f6dSSteven Whitehouse tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs); 273b3b94faaSDavid Teigland ind_blocks += tmp_blocks; 274b3b94faaSDavid Teigland } 275b3b94faaSDavid Teigland 276b3b94faaSDavid Teigland leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH; 277b3b94faaSDavid Teigland 278b3b94faaSDavid Teigland sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks; 279b3b94faaSDavid Teigland 280b3b94faaSDavid Teigland sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize - 281b3b94faaSDavid Teigland sizeof(struct gfs2_dinode); 282b3b94faaSDavid Teigland sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs; 283b3b94faaSDavid Teigland for (x = 2;; x++) { 284b3b94faaSDavid Teigland uint64_t space, d; 285b3b94faaSDavid Teigland uint32_t m; 286b3b94faaSDavid Teigland 287b3b94faaSDavid Teigland space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs; 288b3b94faaSDavid Teigland d = space; 289b3b94faaSDavid Teigland m = do_div(d, sdp->sd_inptrs); 290b3b94faaSDavid Teigland 291b3b94faaSDavid Teigland if (d != sdp->sd_heightsize[x - 1] || m) 292b3b94faaSDavid Teigland break; 293b3b94faaSDavid Teigland sdp->sd_heightsize[x] = space; 294b3b94faaSDavid Teigland } 295b3b94faaSDavid Teigland sdp->sd_max_height = x; 296b3b94faaSDavid Teigland gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); 297b3b94faaSDavid Teigland 298b3b94faaSDavid Teigland sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - 299b3b94faaSDavid Teigland sizeof(struct gfs2_dinode); 300b3b94faaSDavid Teigland sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs; 301b3b94faaSDavid Teigland for (x = 2;; x++) { 302b3b94faaSDavid Teigland uint64_t space, d; 303b3b94faaSDavid Teigland uint32_t m; 304b3b94faaSDavid Teigland 305b3b94faaSDavid Teigland space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs; 306b3b94faaSDavid Teigland d = space; 307b3b94faaSDavid Teigland m = do_div(d, sdp->sd_inptrs); 308b3b94faaSDavid Teigland 309b3b94faaSDavid Teigland if (d != sdp->sd_jheightsize[x - 1] || m) 310b3b94faaSDavid Teigland break; 311b3b94faaSDavid Teigland sdp->sd_jheightsize[x] = space; 312b3b94faaSDavid Teigland } 313b3b94faaSDavid Teigland sdp->sd_max_jheight = x; 314b3b94faaSDavid Teigland gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); 315b3b94faaSDavid Teigland 316b3b94faaSDavid Teigland return 0; 317b3b94faaSDavid Teigland } 318b3b94faaSDavid Teigland 319b3b94faaSDavid Teigland /** 320b3b94faaSDavid Teigland * gfs2_jindex_hold - Grab a lock on the jindex 321b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 322b3b94faaSDavid Teigland * @ji_gh: the holder for the jindex glock 323b3b94faaSDavid Teigland * 324b3b94faaSDavid Teigland * This is very similar to the gfs2_rindex_hold() function, except that 325b3b94faaSDavid Teigland * in general we hold the jindex lock for longer periods of time and 326b3b94faaSDavid Teigland * we grab it far less frequently (in general) then the rgrp lock. 327b3b94faaSDavid Teigland * 328b3b94faaSDavid Teigland * Returns: errno 329b3b94faaSDavid Teigland */ 330b3b94faaSDavid Teigland 331b3b94faaSDavid Teigland int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) 332b3b94faaSDavid Teigland { 333feaa7bbaSSteven Whitehouse struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex); 334b3b94faaSDavid Teigland struct qstr name; 335b3b94faaSDavid Teigland char buf[20]; 336b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 337b3b94faaSDavid Teigland int error; 338b3b94faaSDavid Teigland 339b3b94faaSDavid Teigland name.name = buf; 340b3b94faaSDavid Teigland 341f55ab26aSSteven Whitehouse mutex_lock(&sdp->sd_jindex_mutex); 342b3b94faaSDavid Teigland 343b3b94faaSDavid Teigland for (;;) { 344b3b94faaSDavid Teigland error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 345b3b94faaSDavid Teigland GL_LOCAL_EXCL, ji_gh); 346b3b94faaSDavid Teigland if (error) 347b3b94faaSDavid Teigland break; 348b3b94faaSDavid Teigland 349b3b94faaSDavid Teigland name.len = sprintf(buf, "journal%u", sdp->sd_journals); 350c752666cSSteven Whitehouse name.hash = gfs2_disk_hash(name.name, name.len); 351b3b94faaSDavid Teigland 352feaa7bbaSSteven Whitehouse error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL); 353b3b94faaSDavid Teigland if (error == -ENOENT) { 354b3b94faaSDavid Teigland error = 0; 355b3b94faaSDavid Teigland break; 356b3b94faaSDavid Teigland } 357b3b94faaSDavid Teigland 358b3b94faaSDavid Teigland gfs2_glock_dq_uninit(ji_gh); 359b3b94faaSDavid Teigland 360b3b94faaSDavid Teigland if (error) 361b3b94faaSDavid Teigland break; 362b3b94faaSDavid Teigland 363b3b94faaSDavid Teigland error = -ENOMEM; 364b3b94faaSDavid Teigland jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL); 365b3b94faaSDavid Teigland if (!jd) 366b3b94faaSDavid Teigland break; 367b3b94faaSDavid Teigland 368c752666cSSteven Whitehouse jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL); 369c752666cSSteven Whitehouse if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { 370c752666cSSteven Whitehouse if (!jd->jd_inode) 371c752666cSSteven Whitehouse error = -ENOENT; 372c752666cSSteven Whitehouse else 373c752666cSSteven Whitehouse error = PTR_ERR(jd->jd_inode); 374b3b94faaSDavid Teigland kfree(jd); 375b3b94faaSDavid Teigland break; 376b3b94faaSDavid Teigland } 377b3b94faaSDavid Teigland 378b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 379b3b94faaSDavid Teigland jd->jd_jid = sdp->sd_journals++; 380b3b94faaSDavid Teigland list_add_tail(&jd->jd_list, &sdp->sd_jindex_list); 381b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 382b3b94faaSDavid Teigland } 383b3b94faaSDavid Teigland 384f55ab26aSSteven Whitehouse mutex_unlock(&sdp->sd_jindex_mutex); 385b3b94faaSDavid Teigland 386b3b94faaSDavid Teigland return error; 387b3b94faaSDavid Teigland } 388b3b94faaSDavid Teigland 389b3b94faaSDavid Teigland /** 390b3b94faaSDavid Teigland * gfs2_jindex_free - Clear all the journal index information 391b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 392b3b94faaSDavid Teigland * 393b3b94faaSDavid Teigland */ 394b3b94faaSDavid Teigland 395b3b94faaSDavid Teigland void gfs2_jindex_free(struct gfs2_sbd *sdp) 396b3b94faaSDavid Teigland { 397b3b94faaSDavid Teigland struct list_head list; 398b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 399b3b94faaSDavid Teigland 400b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 401b3b94faaSDavid Teigland list_add(&list, &sdp->sd_jindex_list); 402b3b94faaSDavid Teigland list_del_init(&sdp->sd_jindex_list); 403b3b94faaSDavid Teigland sdp->sd_journals = 0; 404b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 405b3b94faaSDavid Teigland 406b3b94faaSDavid Teigland while (!list_empty(&list)) { 407b3b94faaSDavid Teigland jd = list_entry(list.next, struct gfs2_jdesc, jd_list); 408b3b94faaSDavid Teigland list_del(&jd->jd_list); 4097359a19cSSteven Whitehouse iput(jd->jd_inode); 410b3b94faaSDavid Teigland kfree(jd); 411b3b94faaSDavid Teigland } 412b3b94faaSDavid Teigland } 413b3b94faaSDavid Teigland 414b3b94faaSDavid Teigland static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid) 415b3b94faaSDavid Teigland { 416b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 417b3b94faaSDavid Teigland int found = 0; 418b3b94faaSDavid Teigland 419b3b94faaSDavid Teigland list_for_each_entry(jd, head, jd_list) { 420b3b94faaSDavid Teigland if (jd->jd_jid == jid) { 421b3b94faaSDavid Teigland found = 1; 422b3b94faaSDavid Teigland break; 423b3b94faaSDavid Teigland } 424b3b94faaSDavid Teigland } 425b3b94faaSDavid Teigland 426b3b94faaSDavid Teigland if (!found) 427b3b94faaSDavid Teigland jd = NULL; 428b3b94faaSDavid Teigland 429b3b94faaSDavid Teigland return jd; 430b3b94faaSDavid Teigland } 431b3b94faaSDavid Teigland 432b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid) 433b3b94faaSDavid Teigland { 434b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 435b3b94faaSDavid Teigland 436b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 437b3b94faaSDavid Teigland jd = jdesc_find_i(&sdp->sd_jindex_list, jid); 438b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 439b3b94faaSDavid Teigland 440b3b94faaSDavid Teigland return jd; 441b3b94faaSDavid Teigland } 442b3b94faaSDavid Teigland 443b3b94faaSDavid Teigland void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) 444b3b94faaSDavid Teigland { 445b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 446b3b94faaSDavid Teigland 447b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 448b3b94faaSDavid Teigland jd = jdesc_find_i(&sdp->sd_jindex_list, jid); 449b3b94faaSDavid Teigland if (jd) 450b3b94faaSDavid Teigland jd->jd_dirty = 1; 451b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 452b3b94faaSDavid Teigland } 453b3b94faaSDavid Teigland 454b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) 455b3b94faaSDavid Teigland { 456b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 457b3b94faaSDavid Teigland int found = 0; 458b3b94faaSDavid Teigland 459b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 460b3b94faaSDavid Teigland 461b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 462b3b94faaSDavid Teigland if (jd->jd_dirty) { 463b3b94faaSDavid Teigland jd->jd_dirty = 0; 464b3b94faaSDavid Teigland found = 1; 465b3b94faaSDavid Teigland break; 466b3b94faaSDavid Teigland } 467b3b94faaSDavid Teigland } 468b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 469b3b94faaSDavid Teigland 470b3b94faaSDavid Teigland if (!found) 471b3b94faaSDavid Teigland jd = NULL; 472b3b94faaSDavid Teigland 473b3b94faaSDavid Teigland return jd; 474b3b94faaSDavid Teigland } 475b3b94faaSDavid Teigland 476b3b94faaSDavid Teigland int gfs2_jdesc_check(struct gfs2_jdesc *jd) 477b3b94faaSDavid Teigland { 478feaa7bbaSSteven Whitehouse struct gfs2_inode *ip = GFS2_I(jd->jd_inode); 479feaa7bbaSSteven Whitehouse struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); 480b3b94faaSDavid Teigland int ar; 481b3b94faaSDavid Teigland int error; 482b3b94faaSDavid Teigland 483feaa7bbaSSteven Whitehouse if (ip->i_di.di_size < (8 << 20) || ip->i_di.di_size > (1 << 30) || 484b3b94faaSDavid Teigland (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) { 485b3b94faaSDavid Teigland gfs2_consist_inode(ip); 486b3b94faaSDavid Teigland return -EIO; 487b3b94faaSDavid Teigland } 488b3b94faaSDavid Teigland jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; 489b3b94faaSDavid Teigland 490feaa7bbaSSteven Whitehouse error = gfs2_write_alloc_required(ip, 0, ip->i_di.di_size, &ar); 491b3b94faaSDavid Teigland if (!error && ar) { 492b3b94faaSDavid Teigland gfs2_consist_inode(ip); 493b3b94faaSDavid Teigland error = -EIO; 494b3b94faaSDavid Teigland } 495b3b94faaSDavid Teigland 496b3b94faaSDavid Teigland return error; 497b3b94faaSDavid Teigland } 498b3b94faaSDavid Teigland 499b3b94faaSDavid Teigland /** 500b3b94faaSDavid Teigland * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one 501b3b94faaSDavid Teigland * @sdp: the filesystem 502b3b94faaSDavid Teigland * 503b3b94faaSDavid Teigland * Returns: errno 504b3b94faaSDavid Teigland */ 505b3b94faaSDavid Teigland 506b3b94faaSDavid Teigland int gfs2_make_fs_rw(struct gfs2_sbd *sdp) 507b3b94faaSDavid Teigland { 508feaa7bbaSSteven Whitehouse struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); 5095c676f6dSSteven Whitehouse struct gfs2_glock *j_gl = ip->i_gl; 510b3b94faaSDavid Teigland struct gfs2_holder t_gh; 511b3b94faaSDavid Teigland struct gfs2_log_header head; 512b3b94faaSDavid Teigland int error; 513b3b94faaSDavid Teigland 514b3b94faaSDavid Teigland error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 515579b78a4SSteven Whitehouse GL_LOCAL_EXCL, &t_gh); 516b3b94faaSDavid Teigland if (error) 517b3b94faaSDavid Teigland return error; 518b3b94faaSDavid Teigland 5195c676f6dSSteven Whitehouse gfs2_meta_cache_flush(ip); 520b3b94faaSDavid Teigland j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); 521b3b94faaSDavid Teigland 522b3b94faaSDavid Teigland error = gfs2_find_jhead(sdp->sd_jdesc, &head); 523b3b94faaSDavid Teigland if (error) 524b3b94faaSDavid Teigland goto fail; 525b3b94faaSDavid Teigland 526b3b94faaSDavid Teigland if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { 527b3b94faaSDavid Teigland gfs2_consist(sdp); 528b3b94faaSDavid Teigland error = -EIO; 529b3b94faaSDavid Teigland goto fail; 530b3b94faaSDavid Teigland } 531b3b94faaSDavid Teigland 532b3b94faaSDavid Teigland /* Initialize some head of the log stuff */ 533b3b94faaSDavid Teigland sdp->sd_log_sequence = head.lh_sequence + 1; 534b3b94faaSDavid Teigland gfs2_log_pointers_init(sdp, head.lh_blkno); 535b3b94faaSDavid Teigland 536b3b94faaSDavid Teigland error = gfs2_quota_init(sdp); 537b3b94faaSDavid Teigland if (error) 538a91ea69fSSteven Whitehouse goto fail; 539b3b94faaSDavid Teigland 540b3b94faaSDavid Teigland set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); 541b3b94faaSDavid Teigland 542b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&t_gh); 543b3b94faaSDavid Teigland 544b3b94faaSDavid Teigland return 0; 545b3b94faaSDavid Teigland 546b3b94faaSDavid Teigland fail: 547b3b94faaSDavid Teigland t_gh.gh_flags |= GL_NOCACHE; 548b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&t_gh); 549b3b94faaSDavid Teigland 550b3b94faaSDavid Teigland return error; 551b3b94faaSDavid Teigland } 552b3b94faaSDavid Teigland 553b3b94faaSDavid Teigland /** 554b3b94faaSDavid Teigland * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one 555b3b94faaSDavid Teigland * @sdp: the filesystem 556b3b94faaSDavid Teigland * 557b3b94faaSDavid Teigland * Returns: errno 558b3b94faaSDavid Teigland */ 559b3b94faaSDavid Teigland 560b3b94faaSDavid Teigland int gfs2_make_fs_ro(struct gfs2_sbd *sdp) 561b3b94faaSDavid Teigland { 562b3b94faaSDavid Teigland struct gfs2_holder t_gh; 563b3b94faaSDavid Teigland int error; 564b3b94faaSDavid Teigland 565b3b94faaSDavid Teigland gfs2_quota_sync(sdp); 566b3b94faaSDavid Teigland gfs2_statfs_sync(sdp); 567b3b94faaSDavid Teigland 568b3b94faaSDavid Teigland error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 569579b78a4SSteven Whitehouse GL_LOCAL_EXCL | GL_NOCACHE, 570b3b94faaSDavid Teigland &t_gh); 571b3b94faaSDavid Teigland if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) 572b3b94faaSDavid Teigland return error; 573b3b94faaSDavid Teigland 574b3b94faaSDavid Teigland gfs2_meta_syncfs(sdp); 575b3b94faaSDavid Teigland gfs2_log_shutdown(sdp); 576b3b94faaSDavid Teigland 577b3b94faaSDavid Teigland clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); 578b3b94faaSDavid Teigland 579b3b94faaSDavid Teigland if (t_gh.gh_gl) 580b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&t_gh); 581b3b94faaSDavid Teigland 582b3b94faaSDavid Teigland gfs2_quota_cleanup(sdp); 583b3b94faaSDavid Teigland 584b3b94faaSDavid Teigland return error; 585b3b94faaSDavid Teigland } 586b3b94faaSDavid Teigland 587b3b94faaSDavid Teigland int gfs2_statfs_init(struct gfs2_sbd *sdp) 588b3b94faaSDavid Teigland { 589feaa7bbaSSteven Whitehouse struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); 590b3b94faaSDavid Teigland struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; 591feaa7bbaSSteven Whitehouse struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); 592b3b94faaSDavid Teigland struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; 593b3b94faaSDavid Teigland struct buffer_head *m_bh, *l_bh; 594b3b94faaSDavid Teigland struct gfs2_holder gh; 595b3b94faaSDavid Teigland int error; 596b3b94faaSDavid Teigland 597b3b94faaSDavid Teigland error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, 598b3b94faaSDavid Teigland &gh); 599b3b94faaSDavid Teigland if (error) 600b3b94faaSDavid Teigland return error; 601b3b94faaSDavid Teigland 602b3b94faaSDavid Teigland error = gfs2_meta_inode_buffer(m_ip, &m_bh); 603b3b94faaSDavid Teigland if (error) 604b3b94faaSDavid Teigland goto out; 605b3b94faaSDavid Teigland 606b3b94faaSDavid Teigland if (sdp->sd_args.ar_spectator) { 607b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 608b3b94faaSDavid Teigland gfs2_statfs_change_in(m_sc, m_bh->b_data + 609b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)); 610b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 611b3b94faaSDavid Teigland } else { 612b3b94faaSDavid Teigland error = gfs2_meta_inode_buffer(l_ip, &l_bh); 613b3b94faaSDavid Teigland if (error) 614b3b94faaSDavid Teigland goto out_m_bh; 615b3b94faaSDavid Teigland 616b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 617b3b94faaSDavid Teigland gfs2_statfs_change_in(m_sc, m_bh->b_data + 618b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)); 619b3b94faaSDavid Teigland gfs2_statfs_change_in(l_sc, l_bh->b_data + 620b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)); 621b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 622b3b94faaSDavid Teigland 623b3b94faaSDavid Teigland brelse(l_bh); 624b3b94faaSDavid Teigland } 625b3b94faaSDavid Teigland 626b3b94faaSDavid Teigland out_m_bh: 627b3b94faaSDavid Teigland brelse(m_bh); 628b3b94faaSDavid Teigland out: 629b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&gh); 630b3b94faaSDavid Teigland return 0; 631b3b94faaSDavid Teigland } 632b3b94faaSDavid Teigland 633b3b94faaSDavid Teigland void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, 634b3b94faaSDavid Teigland int64_t dinodes) 635b3b94faaSDavid Teigland { 636feaa7bbaSSteven Whitehouse struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); 637b3b94faaSDavid Teigland struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; 638b3b94faaSDavid Teigland struct buffer_head *l_bh; 639b3b94faaSDavid Teigland int error; 640b3b94faaSDavid Teigland 641b3b94faaSDavid Teigland error = gfs2_meta_inode_buffer(l_ip, &l_bh); 642b3b94faaSDavid Teigland if (error) 643b3b94faaSDavid Teigland return; 644b3b94faaSDavid Teigland 645f55ab26aSSteven Whitehouse mutex_lock(&sdp->sd_statfs_mutex); 646d4e9c4c3SSteven Whitehouse gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); 647f55ab26aSSteven Whitehouse mutex_unlock(&sdp->sd_statfs_mutex); 648b3b94faaSDavid Teigland 649b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 650b3b94faaSDavid Teigland l_sc->sc_total += total; 651b3b94faaSDavid Teigland l_sc->sc_free += free; 652b3b94faaSDavid Teigland l_sc->sc_dinodes += dinodes; 653b3b94faaSDavid Teigland gfs2_statfs_change_out(l_sc, l_bh->b_data + 654b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)); 655b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 656b3b94faaSDavid Teigland 657b3b94faaSDavid Teigland brelse(l_bh); 658b3b94faaSDavid Teigland } 659b3b94faaSDavid Teigland 660b3b94faaSDavid Teigland int gfs2_statfs_sync(struct gfs2_sbd *sdp) 661b3b94faaSDavid Teigland { 662feaa7bbaSSteven Whitehouse struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); 663feaa7bbaSSteven Whitehouse struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); 664b3b94faaSDavid Teigland struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; 665b3b94faaSDavid Teigland struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; 666b3b94faaSDavid Teigland struct gfs2_holder gh; 667b3b94faaSDavid Teigland struct buffer_head *m_bh, *l_bh; 668b3b94faaSDavid Teigland int error; 669b3b94faaSDavid Teigland 670b3b94faaSDavid Teigland error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, 671b3b94faaSDavid Teigland &gh); 672b3b94faaSDavid Teigland if (error) 673b3b94faaSDavid Teigland return error; 674b3b94faaSDavid Teigland 675b3b94faaSDavid Teigland error = gfs2_meta_inode_buffer(m_ip, &m_bh); 676b3b94faaSDavid Teigland if (error) 677b3b94faaSDavid Teigland goto out; 678b3b94faaSDavid Teigland 679b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 680b3b94faaSDavid Teigland gfs2_statfs_change_in(m_sc, m_bh->b_data + 681b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)); 682b3b94faaSDavid Teigland if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) { 683b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 684b3b94faaSDavid Teigland goto out_bh; 685b3b94faaSDavid Teigland } 686b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 687b3b94faaSDavid Teigland 688b3b94faaSDavid Teigland error = gfs2_meta_inode_buffer(l_ip, &l_bh); 689b3b94faaSDavid Teigland if (error) 690b3b94faaSDavid Teigland goto out_bh; 691b3b94faaSDavid Teigland 692b3b94faaSDavid Teigland error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); 693b3b94faaSDavid Teigland if (error) 694b3b94faaSDavid Teigland goto out_bh2; 695b3b94faaSDavid Teigland 696f55ab26aSSteven Whitehouse mutex_lock(&sdp->sd_statfs_mutex); 697d4e9c4c3SSteven Whitehouse gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); 698f55ab26aSSteven Whitehouse mutex_unlock(&sdp->sd_statfs_mutex); 699b3b94faaSDavid Teigland 700b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 701b3b94faaSDavid Teigland m_sc->sc_total += l_sc->sc_total; 702b3b94faaSDavid Teigland m_sc->sc_free += l_sc->sc_free; 703b3b94faaSDavid Teigland m_sc->sc_dinodes += l_sc->sc_dinodes; 704b3b94faaSDavid Teigland memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); 705b3b94faaSDavid Teigland memset(l_bh->b_data + sizeof(struct gfs2_dinode), 706b3b94faaSDavid Teigland 0, sizeof(struct gfs2_statfs_change)); 707b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 708b3b94faaSDavid Teigland 709d4e9c4c3SSteven Whitehouse gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); 710b3b94faaSDavid Teigland gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); 711b3b94faaSDavid Teigland 712b3b94faaSDavid Teigland gfs2_trans_end(sdp); 713b3b94faaSDavid Teigland 714b3b94faaSDavid Teigland out_bh2: 715b3b94faaSDavid Teigland brelse(l_bh); 716b3b94faaSDavid Teigland out_bh: 717b3b94faaSDavid Teigland brelse(m_bh); 718b3b94faaSDavid Teigland out: 719b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&gh); 720b3b94faaSDavid Teigland return error; 721b3b94faaSDavid Teigland } 722b3b94faaSDavid Teigland 723b3b94faaSDavid Teigland /** 724b3b94faaSDavid Teigland * gfs2_statfs_i - Do a statfs 725b3b94faaSDavid Teigland * @sdp: the filesystem 726b3b94faaSDavid Teigland * @sg: the sg structure 727b3b94faaSDavid Teigland * 728b3b94faaSDavid Teigland * Returns: errno 729b3b94faaSDavid Teigland */ 730b3b94faaSDavid Teigland 731b3b94faaSDavid Teigland int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) 732b3b94faaSDavid Teigland { 733b3b94faaSDavid Teigland struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; 734b3b94faaSDavid Teigland struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; 735b3b94faaSDavid Teigland 736b3b94faaSDavid Teigland spin_lock(&sdp->sd_statfs_spin); 737b3b94faaSDavid Teigland 738b3b94faaSDavid Teigland *sc = *m_sc; 739b3b94faaSDavid Teigland sc->sc_total += l_sc->sc_total; 740b3b94faaSDavid Teigland sc->sc_free += l_sc->sc_free; 741b3b94faaSDavid Teigland sc->sc_dinodes += l_sc->sc_dinodes; 742b3b94faaSDavid Teigland 743b3b94faaSDavid Teigland spin_unlock(&sdp->sd_statfs_spin); 744b3b94faaSDavid Teigland 745b3b94faaSDavid Teigland if (sc->sc_free < 0) 746b3b94faaSDavid Teigland sc->sc_free = 0; 747b3b94faaSDavid Teigland if (sc->sc_free > sc->sc_total) 748b3b94faaSDavid Teigland sc->sc_free = sc->sc_total; 749b3b94faaSDavid Teigland if (sc->sc_dinodes < 0) 750b3b94faaSDavid Teigland sc->sc_dinodes = 0; 751b3b94faaSDavid Teigland 752b3b94faaSDavid Teigland return 0; 753b3b94faaSDavid Teigland } 754b3b94faaSDavid Teigland 755b3b94faaSDavid Teigland /** 756b3b94faaSDavid Teigland * statfs_fill - fill in the sg for a given RG 757b3b94faaSDavid Teigland * @rgd: the RG 758b3b94faaSDavid Teigland * @sc: the sc structure 759b3b94faaSDavid Teigland * 760b3b94faaSDavid Teigland * Returns: 0 on success, -ESTALE if the LVB is invalid 761b3b94faaSDavid Teigland */ 762b3b94faaSDavid Teigland 763b3b94faaSDavid Teigland static int statfs_slow_fill(struct gfs2_rgrpd *rgd, 764b3b94faaSDavid Teigland struct gfs2_statfs_change *sc) 765b3b94faaSDavid Teigland { 766b3b94faaSDavid Teigland gfs2_rgrp_verify(rgd); 767b3b94faaSDavid Teigland sc->sc_total += rgd->rd_ri.ri_data; 768b3b94faaSDavid Teigland sc->sc_free += rgd->rd_rg.rg_free; 769b3b94faaSDavid Teigland sc->sc_dinodes += rgd->rd_rg.rg_dinodes; 770b3b94faaSDavid Teigland return 0; 771b3b94faaSDavid Teigland } 772b3b94faaSDavid Teigland 773b3b94faaSDavid Teigland /** 774b3b94faaSDavid Teigland * gfs2_statfs_slow - Stat a filesystem using asynchronous locking 775b3b94faaSDavid Teigland * @sdp: the filesystem 776b3b94faaSDavid Teigland * @sc: the sc info that will be returned 777b3b94faaSDavid Teigland * 778b3b94faaSDavid Teigland * Any error (other than a signal) will cause this routine to fall back 779b3b94faaSDavid Teigland * to the synchronous version. 780b3b94faaSDavid Teigland * 781b3b94faaSDavid Teigland * FIXME: This really shouldn't busy wait like this. 782b3b94faaSDavid Teigland * 783b3b94faaSDavid Teigland * Returns: errno 784b3b94faaSDavid Teigland */ 785b3b94faaSDavid Teigland 786b3b94faaSDavid Teigland int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) 787b3b94faaSDavid Teigland { 788b3b94faaSDavid Teigland struct gfs2_holder ri_gh; 789b3b94faaSDavid Teigland struct gfs2_rgrpd *rgd_next; 790b3b94faaSDavid Teigland struct gfs2_holder *gha, *gh; 791b3b94faaSDavid Teigland unsigned int slots = 64; 792b3b94faaSDavid Teigland unsigned int x; 793b3b94faaSDavid Teigland int done; 794b3b94faaSDavid Teigland int error = 0, err; 795b3b94faaSDavid Teigland 796b3b94faaSDavid Teigland memset(sc, 0, sizeof(struct gfs2_statfs_change)); 797b3b94faaSDavid Teigland gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL); 798b3b94faaSDavid Teigland if (!gha) 799b3b94faaSDavid Teigland return -ENOMEM; 800b3b94faaSDavid Teigland 801b3b94faaSDavid Teigland error = gfs2_rindex_hold(sdp, &ri_gh); 802b3b94faaSDavid Teigland if (error) 803b3b94faaSDavid Teigland goto out; 804b3b94faaSDavid Teigland 805b3b94faaSDavid Teigland rgd_next = gfs2_rgrpd_get_first(sdp); 806b3b94faaSDavid Teigland 807b3b94faaSDavid Teigland for (;;) { 808b3b94faaSDavid Teigland done = 1; 809b3b94faaSDavid Teigland 810b3b94faaSDavid Teigland for (x = 0; x < slots; x++) { 811b3b94faaSDavid Teigland gh = gha + x; 812b3b94faaSDavid Teigland 813b3b94faaSDavid Teigland if (gh->gh_gl && gfs2_glock_poll(gh)) { 814b3b94faaSDavid Teigland err = gfs2_glock_wait(gh); 815b3b94faaSDavid Teigland if (err) { 816b3b94faaSDavid Teigland gfs2_holder_uninit(gh); 817b3b94faaSDavid Teigland error = err; 818b3b94faaSDavid Teigland } else { 819b3b94faaSDavid Teigland if (!error) 8205c676f6dSSteven Whitehouse error = statfs_slow_fill( 8215c676f6dSSteven Whitehouse gh->gh_gl->gl_object, sc); 822b3b94faaSDavid Teigland gfs2_glock_dq_uninit(gh); 823b3b94faaSDavid Teigland } 824b3b94faaSDavid Teigland } 825b3b94faaSDavid Teigland 826b3b94faaSDavid Teigland if (gh->gh_gl) 827b3b94faaSDavid Teigland done = 0; 828b3b94faaSDavid Teigland else if (rgd_next && !error) { 829b3b94faaSDavid Teigland error = gfs2_glock_nq_init(rgd_next->rd_gl, 830b3b94faaSDavid Teigland LM_ST_SHARED, 831b3b94faaSDavid Teigland GL_ASYNC, 832b3b94faaSDavid Teigland gh); 833b3b94faaSDavid Teigland rgd_next = gfs2_rgrpd_get_next(rgd_next); 834b3b94faaSDavid Teigland done = 0; 835b3b94faaSDavid Teigland } 836b3b94faaSDavid Teigland 837b3b94faaSDavid Teigland if (signal_pending(current)) 838b3b94faaSDavid Teigland error = -ERESTARTSYS; 839b3b94faaSDavid Teigland } 840b3b94faaSDavid Teigland 841b3b94faaSDavid Teigland if (done) 842b3b94faaSDavid Teigland break; 843b3b94faaSDavid Teigland 844b3b94faaSDavid Teigland yield(); 845b3b94faaSDavid Teigland } 846b3b94faaSDavid Teigland 847b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&ri_gh); 848b3b94faaSDavid Teigland 849b3b94faaSDavid Teigland out: 850b3b94faaSDavid Teigland kfree(gha); 851b3b94faaSDavid Teigland return error; 852b3b94faaSDavid Teigland } 853b3b94faaSDavid Teigland 854b3b94faaSDavid Teigland struct lfcc { 855b3b94faaSDavid Teigland struct list_head list; 856b3b94faaSDavid Teigland struct gfs2_holder gh; 857b3b94faaSDavid Teigland }; 858b3b94faaSDavid Teigland 859b3b94faaSDavid Teigland /** 860b3b94faaSDavid Teigland * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all 861b3b94faaSDavid Teigland * journals are clean 862b3b94faaSDavid Teigland * @sdp: the file system 863b3b94faaSDavid Teigland * @state: the state to put the transaction lock into 864b3b94faaSDavid Teigland * @t_gh: the hold on the transaction lock 865b3b94faaSDavid Teigland * 866b3b94faaSDavid Teigland * Returns: errno 867b3b94faaSDavid Teigland */ 868b3b94faaSDavid Teigland 86908bc2dbcSAdrian Bunk static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, 87008bc2dbcSAdrian Bunk struct gfs2_holder *t_gh) 871b3b94faaSDavid Teigland { 8725c676f6dSSteven Whitehouse struct gfs2_inode *ip; 873b3b94faaSDavid Teigland struct gfs2_holder ji_gh; 874b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 875b3b94faaSDavid Teigland struct lfcc *lfcc; 876b3b94faaSDavid Teigland LIST_HEAD(list); 877b3b94faaSDavid Teigland struct gfs2_log_header lh; 878b3b94faaSDavid Teigland int error; 879b3b94faaSDavid Teigland 880b3b94faaSDavid Teigland error = gfs2_jindex_hold(sdp, &ji_gh); 881b3b94faaSDavid Teigland if (error) 882b3b94faaSDavid Teigland return error; 883b3b94faaSDavid Teigland 884b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 885b3b94faaSDavid Teigland lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL); 886b3b94faaSDavid Teigland if (!lfcc) { 887b3b94faaSDavid Teigland error = -ENOMEM; 888b3b94faaSDavid Teigland goto out; 889b3b94faaSDavid Teigland } 890feaa7bbaSSteven Whitehouse ip = GFS2_I(jd->jd_inode); 891feaa7bbaSSteven Whitehouse error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh); 892b3b94faaSDavid Teigland if (error) { 893b3b94faaSDavid Teigland kfree(lfcc); 894b3b94faaSDavid Teigland goto out; 895b3b94faaSDavid Teigland } 896b3b94faaSDavid Teigland list_add(&lfcc->list, &list); 897b3b94faaSDavid Teigland } 898b3b94faaSDavid Teigland 899b3b94faaSDavid Teigland error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED, 900579b78a4SSteven Whitehouse LM_FLAG_PRIORITY | GL_NOCACHE, 901b3b94faaSDavid Teigland t_gh); 902b3b94faaSDavid Teigland 903b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 904b3b94faaSDavid Teigland error = gfs2_jdesc_check(jd); 905b3b94faaSDavid Teigland if (error) 906b3b94faaSDavid Teigland break; 907b3b94faaSDavid Teigland error = gfs2_find_jhead(jd, &lh); 908b3b94faaSDavid Teigland if (error) 909b3b94faaSDavid Teigland break; 910b3b94faaSDavid Teigland if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { 911b3b94faaSDavid Teigland error = -EBUSY; 912b3b94faaSDavid Teigland break; 913b3b94faaSDavid Teigland } 914b3b94faaSDavid Teigland } 915b3b94faaSDavid Teigland 916b3b94faaSDavid Teigland if (error) 917b3b94faaSDavid Teigland gfs2_glock_dq_uninit(t_gh); 918b3b94faaSDavid Teigland 919b3b94faaSDavid Teigland out: 920b3b94faaSDavid Teigland while (!list_empty(&list)) { 921b3b94faaSDavid Teigland lfcc = list_entry(list.next, struct lfcc, list); 922b3b94faaSDavid Teigland list_del(&lfcc->list); 923b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&lfcc->gh); 924b3b94faaSDavid Teigland kfree(lfcc); 925b3b94faaSDavid Teigland } 926b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&ji_gh); 927b3b94faaSDavid Teigland return error; 928b3b94faaSDavid Teigland } 929b3b94faaSDavid Teigland 930b3b94faaSDavid Teigland /** 931b3b94faaSDavid Teigland * gfs2_freeze_fs - freezes the file system 932b3b94faaSDavid Teigland * @sdp: the file system 933b3b94faaSDavid Teigland * 934b3b94faaSDavid Teigland * This function flushes data and meta data for all machines by 935b3b94faaSDavid Teigland * aquiring the transaction log exclusively. All journals are 936b3b94faaSDavid Teigland * ensured to be in a clean state as well. 937b3b94faaSDavid Teigland * 938b3b94faaSDavid Teigland * Returns: errno 939b3b94faaSDavid Teigland */ 940b3b94faaSDavid Teigland 941b3b94faaSDavid Teigland int gfs2_freeze_fs(struct gfs2_sbd *sdp) 942b3b94faaSDavid Teigland { 943b3b94faaSDavid Teigland int error = 0; 944b3b94faaSDavid Teigland 945f55ab26aSSteven Whitehouse mutex_lock(&sdp->sd_freeze_lock); 946b3b94faaSDavid Teigland 947b3b94faaSDavid Teigland if (!sdp->sd_freeze_count++) { 948b3b94faaSDavid Teigland error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh); 949b3b94faaSDavid Teigland if (error) 950b3b94faaSDavid Teigland sdp->sd_freeze_count--; 951b3b94faaSDavid Teigland } 952b3b94faaSDavid Teigland 953f55ab26aSSteven Whitehouse mutex_unlock(&sdp->sd_freeze_lock); 954b3b94faaSDavid Teigland 955b3b94faaSDavid Teigland return error; 956b3b94faaSDavid Teigland } 957b3b94faaSDavid Teigland 958b3b94faaSDavid Teigland /** 959b3b94faaSDavid Teigland * gfs2_unfreeze_fs - unfreezes the file system 960b3b94faaSDavid Teigland * @sdp: the file system 961b3b94faaSDavid Teigland * 962b3b94faaSDavid Teigland * This function allows the file system to proceed by unlocking 963b3b94faaSDavid Teigland * the exclusively held transaction lock. Other GFS2 nodes are 964b3b94faaSDavid Teigland * now free to acquire the lock shared and go on with their lives. 965b3b94faaSDavid Teigland * 966b3b94faaSDavid Teigland */ 967b3b94faaSDavid Teigland 968b3b94faaSDavid Teigland void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) 969b3b94faaSDavid Teigland { 970f55ab26aSSteven Whitehouse mutex_lock(&sdp->sd_freeze_lock); 971b3b94faaSDavid Teigland 972b3b94faaSDavid Teigland if (sdp->sd_freeze_count && !--sdp->sd_freeze_count) 973b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); 974b3b94faaSDavid Teigland 975f55ab26aSSteven Whitehouse mutex_unlock(&sdp->sd_freeze_lock); 976b3b94faaSDavid Teigland } 977b3b94faaSDavid Teigland 978