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