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