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> 15b3b94faaSDavid Teigland #include <asm/semaphore.h> 16b3b94faaSDavid Teigland 17b3b94faaSDavid Teigland #include "gfs2.h" 18b3b94faaSDavid Teigland #include "bmap.h" 19b3b94faaSDavid Teigland #include "dir.h" 20b3b94faaSDavid Teigland #include "format.h" 21b3b94faaSDavid Teigland #include "glock.h" 22b3b94faaSDavid Teigland #include "glops.h" 23b3b94faaSDavid Teigland #include "inode.h" 24b3b94faaSDavid Teigland #include "log.h" 25b3b94faaSDavid Teigland #include "meta_io.h" 26b3b94faaSDavid Teigland #include "quota.h" 27b3b94faaSDavid Teigland #include "recovery.h" 28b3b94faaSDavid Teigland #include "rgrp.h" 29b3b94faaSDavid Teigland #include "super.h" 30b3b94faaSDavid Teigland #include "trans.h" 31b3b94faaSDavid Teigland #include "unlinked.h" 32b3b94faaSDavid Teigland 33b3b94faaSDavid Teigland /** 34b3b94faaSDavid Teigland * gfs2_tune_init - Fill a gfs2_tune structure with default values 35b3b94faaSDavid Teigland * @gt: tune 36b3b94faaSDavid Teigland * 37b3b94faaSDavid Teigland */ 38b3b94faaSDavid Teigland 39b3b94faaSDavid Teigland void gfs2_tune_init(struct gfs2_tune *gt) 40b3b94faaSDavid Teigland { 41b3b94faaSDavid Teigland spin_lock_init(>->gt_spin); 42b3b94faaSDavid Teigland 43b3b94faaSDavid Teigland gt->gt_ilimit = 100; 44b3b94faaSDavid Teigland gt->gt_ilimit_tries = 3; 45b3b94faaSDavid Teigland gt->gt_ilimit_min = 1; 46b3b94faaSDavid Teigland gt->gt_demote_secs = 300; 47b3b94faaSDavid Teigland gt->gt_incore_log_blocks = 1024; 48b3b94faaSDavid Teigland gt->gt_log_flush_secs = 60; 49b3b94faaSDavid Teigland gt->gt_jindex_refresh_secs = 60; 50b3b94faaSDavid Teigland gt->gt_scand_secs = 15; 51b3b94faaSDavid Teigland gt->gt_recoverd_secs = 60; 52b3b94faaSDavid Teigland gt->gt_logd_secs = 1; 53b3b94faaSDavid Teigland gt->gt_quotad_secs = 5; 54b3b94faaSDavid Teigland gt->gt_inoded_secs = 15; 55b3b94faaSDavid Teigland gt->gt_quota_simul_sync = 64; 56b3b94faaSDavid Teigland gt->gt_quota_warn_period = 10; 57b3b94faaSDavid Teigland gt->gt_quota_scale_num = 1; 58b3b94faaSDavid Teigland gt->gt_quota_scale_den = 1; 59b3b94faaSDavid Teigland gt->gt_quota_cache_secs = 300; 60b3b94faaSDavid Teigland gt->gt_quota_quantum = 60; 61b3b94faaSDavid Teigland gt->gt_atime_quantum = 3600; 62b3b94faaSDavid Teigland gt->gt_new_files_jdata = 0; 63b3b94faaSDavid Teigland gt->gt_new_files_directio = 0; 64b3b94faaSDavid Teigland gt->gt_max_atomic_write = 4 << 20; 65b3b94faaSDavid Teigland gt->gt_max_readahead = 1 << 18; 66b3b94faaSDavid Teigland gt->gt_lockdump_size = 131072; 67b3b94faaSDavid Teigland gt->gt_stall_secs = 600; 68b3b94faaSDavid Teigland gt->gt_complain_secs = 10; 69b3b94faaSDavid Teigland gt->gt_reclaim_limit = 5000; 70b3b94faaSDavid Teigland gt->gt_entries_per_readdir = 32; 71b3b94faaSDavid Teigland gt->gt_prefetch_secs = 10; 72b3b94faaSDavid Teigland gt->gt_greedy_default = HZ / 10; 73b3b94faaSDavid Teigland gt->gt_greedy_quantum = HZ / 40; 74b3b94faaSDavid Teigland gt->gt_greedy_max = HZ / 4; 75b3b94faaSDavid Teigland gt->gt_statfs_quantum = 30; 76b3b94faaSDavid Teigland gt->gt_statfs_slow = 0; 77b3b94faaSDavid Teigland } 78b3b94faaSDavid Teigland 79b3b94faaSDavid Teigland /** 80b3b94faaSDavid Teigland * gfs2_check_sb - Check superblock 81b3b94faaSDavid Teigland * @sdp: the filesystem 82b3b94faaSDavid Teigland * @sb: The superblock 83b3b94faaSDavid Teigland * @silent: Don't print a message if the check fails 84b3b94faaSDavid Teigland * 85b3b94faaSDavid Teigland * Checks the version code of the FS is one that we understand how to 86b3b94faaSDavid Teigland * read and that the sizes of the various on-disk structures have not 87b3b94faaSDavid Teigland * changed. 88b3b94faaSDavid Teigland */ 89b3b94faaSDavid Teigland 90b3b94faaSDavid Teigland int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) 91b3b94faaSDavid Teigland { 92b3b94faaSDavid Teigland unsigned int x; 93b3b94faaSDavid Teigland 94b3b94faaSDavid Teigland if (sb->sb_header.mh_magic != GFS2_MAGIC || 95b3b94faaSDavid Teigland sb->sb_header.mh_type != GFS2_METATYPE_SB) { 96b3b94faaSDavid Teigland if (!silent) 97b3b94faaSDavid Teigland printk("GFS2: not a GFS2 filesystem\n"); 98b3b94faaSDavid Teigland return -EINVAL; 99b3b94faaSDavid Teigland } 100b3b94faaSDavid Teigland 101b3b94faaSDavid Teigland /* If format numbers match exactly, we're done. */ 102b3b94faaSDavid Teigland 103b3b94faaSDavid Teigland if (sb->sb_fs_format == GFS2_FORMAT_FS && 104b3b94faaSDavid Teigland sb->sb_multihost_format == GFS2_FORMAT_MULTI) 105b3b94faaSDavid Teigland return 0; 106b3b94faaSDavid Teigland 107b3b94faaSDavid Teigland if (sb->sb_fs_format != GFS2_FORMAT_FS) { 108b3b94faaSDavid Teigland for (x = 0; gfs2_old_fs_formats[x]; x++) 109b3b94faaSDavid Teigland if (gfs2_old_fs_formats[x] == sb->sb_fs_format) 110b3b94faaSDavid Teigland break; 111b3b94faaSDavid Teigland 112b3b94faaSDavid Teigland if (!gfs2_old_fs_formats[x]) { 113b3b94faaSDavid Teigland printk("GFS2: code version (%u, %u) is incompatible " 114b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 115b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 116b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 117b3b94faaSDavid Teigland printk("GFS2: I don't know how to upgrade this FS\n"); 118b3b94faaSDavid Teigland return -EINVAL; 119b3b94faaSDavid Teigland } 120b3b94faaSDavid Teigland } 121b3b94faaSDavid Teigland 122b3b94faaSDavid Teigland if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) { 123b3b94faaSDavid Teigland for (x = 0; gfs2_old_multihost_formats[x]; x++) 124b3b94faaSDavid Teigland if (gfs2_old_multihost_formats[x] == sb->sb_multihost_format) 125b3b94faaSDavid Teigland break; 126b3b94faaSDavid Teigland 127b3b94faaSDavid Teigland if (!gfs2_old_multihost_formats[x]) { 128b3b94faaSDavid Teigland printk("GFS2: code version (%u, %u) is incompatible " 129b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 130b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 131b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 132b3b94faaSDavid Teigland printk("GFS2: I don't know how to upgrade this FS\n"); 133b3b94faaSDavid Teigland return -EINVAL; 134b3b94faaSDavid Teigland } 135b3b94faaSDavid Teigland } 136b3b94faaSDavid Teigland 137b3b94faaSDavid Teigland if (!sdp->sd_args.ar_upgrade) { 138b3b94faaSDavid Teigland printk("GFS2: code version (%u, %u) is incompatible " 139b3b94faaSDavid Teigland "with ondisk format (%u, %u)\n", 140b3b94faaSDavid Teigland GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, 141b3b94faaSDavid Teigland sb->sb_fs_format, sb->sb_multihost_format); 142b3b94faaSDavid Teigland printk("GFS2: Use the \"upgrade\" mount option to upgrade " 143b3b94faaSDavid Teigland "the FS\n"); 144b3b94faaSDavid Teigland printk("GFS2: See the manual for more details\n"); 145b3b94faaSDavid Teigland return -EINVAL; 146b3b94faaSDavid Teigland } 147b3b94faaSDavid Teigland 148b3b94faaSDavid Teigland return 0; 149b3b94faaSDavid Teigland } 150b3b94faaSDavid Teigland 151b3b94faaSDavid Teigland /** 152b3b94faaSDavid Teigland * gfs2_read_sb - Read super block 153b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 154b3b94faaSDavid Teigland * @gl: the glock for the superblock (assumed to be held) 155b3b94faaSDavid Teigland * @silent: Don't print message if mount fails 156b3b94faaSDavid Teigland * 157b3b94faaSDavid Teigland */ 158b3b94faaSDavid Teigland 159b3b94faaSDavid Teigland int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) 160b3b94faaSDavid Teigland { 161b3b94faaSDavid Teigland struct buffer_head *bh; 162b3b94faaSDavid Teigland uint32_t hash_blocks, ind_blocks, leaf_blocks; 163b3b94faaSDavid Teigland uint32_t tmp_blocks; 164b3b94faaSDavid Teigland unsigned int x; 165b3b94faaSDavid Teigland int error; 166b3b94faaSDavid Teigland 167b3b94faaSDavid Teigland error = gfs2_meta_read(gl, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, 168b3b94faaSDavid Teigland DIO_FORCE | DIO_START | DIO_WAIT, &bh); 169b3b94faaSDavid Teigland if (error) { 170b3b94faaSDavid Teigland if (!silent) 171b3b94faaSDavid Teigland fs_err(sdp, "can't read superblock\n"); 172b3b94faaSDavid Teigland return error; 173b3b94faaSDavid Teigland } 174b3b94faaSDavid Teigland 175b3b94faaSDavid Teigland gfs2_assert(sdp, sizeof(struct gfs2_sb) <= bh->b_size); 176b3b94faaSDavid Teigland gfs2_sb_in(&sdp->sd_sb, bh->b_data); 177b3b94faaSDavid Teigland brelse(bh); 178b3b94faaSDavid Teigland 179b3b94faaSDavid Teigland error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); 180b3b94faaSDavid Teigland if (error) 181b3b94faaSDavid Teigland return error; 182b3b94faaSDavid Teigland 183b3b94faaSDavid Teigland sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - 184b3b94faaSDavid Teigland GFS2_BASIC_BLOCK_SHIFT; 185b3b94faaSDavid Teigland sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; 186b3b94faaSDavid Teigland sdp->sd_diptrs = (sdp->sd_sb.sb_bsize - 187b3b94faaSDavid Teigland sizeof(struct gfs2_dinode)) / sizeof(uint64_t); 188b3b94faaSDavid Teigland sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - 189b3b94faaSDavid Teigland sizeof(struct gfs2_meta_header)) / sizeof(uint64_t); 190b3b94faaSDavid Teigland sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); 191b3b94faaSDavid Teigland sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2; 192b3b94faaSDavid Teigland sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1; 193b3b94faaSDavid Teigland sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); 194b3b94faaSDavid Teigland sdp->sd_ut_per_block = (sdp->sd_sb.sb_bsize - 195b3b94faaSDavid Teigland sizeof(struct gfs2_meta_header)) / 196b3b94faaSDavid Teigland sizeof(struct gfs2_unlinked_tag); 197b3b94faaSDavid Teigland sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize - 198b3b94faaSDavid Teigland sizeof(struct gfs2_meta_header)) / 199b3b94faaSDavid Teigland sizeof(struct gfs2_quota_change); 200b3b94faaSDavid Teigland 201b3b94faaSDavid Teigland /* Compute maximum reservation required to add a entry to a directory */ 202b3b94faaSDavid Teigland 203b3b94faaSDavid Teigland hash_blocks = DIV_RU(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), 204b3b94faaSDavid Teigland sdp->sd_jbsize); 205b3b94faaSDavid Teigland 206b3b94faaSDavid Teigland ind_blocks = 0; 207b3b94faaSDavid Teigland for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) { 208b3b94faaSDavid Teigland tmp_blocks = DIV_RU(tmp_blocks, sdp->sd_inptrs); 209b3b94faaSDavid Teigland ind_blocks += tmp_blocks; 210b3b94faaSDavid Teigland } 211b3b94faaSDavid Teigland 212b3b94faaSDavid Teigland leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH; 213b3b94faaSDavid Teigland 214b3b94faaSDavid Teigland sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks; 215b3b94faaSDavid Teigland 216b3b94faaSDavid Teigland sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize - 217b3b94faaSDavid Teigland sizeof(struct gfs2_dinode); 218b3b94faaSDavid Teigland sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs; 219b3b94faaSDavid Teigland for (x = 2;; x++) { 220b3b94faaSDavid Teigland uint64_t space, d; 221b3b94faaSDavid Teigland uint32_t m; 222b3b94faaSDavid Teigland 223b3b94faaSDavid Teigland space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs; 224b3b94faaSDavid Teigland d = space; 225b3b94faaSDavid Teigland m = do_div(d, sdp->sd_inptrs); 226b3b94faaSDavid Teigland 227b3b94faaSDavid Teigland if (d != sdp->sd_heightsize[x - 1] || m) 228b3b94faaSDavid Teigland break; 229b3b94faaSDavid Teigland sdp->sd_heightsize[x] = space; 230b3b94faaSDavid Teigland } 231b3b94faaSDavid Teigland sdp->sd_max_height = x; 232b3b94faaSDavid Teigland gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); 233b3b94faaSDavid Teigland 234b3b94faaSDavid Teigland sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - 235b3b94faaSDavid Teigland sizeof(struct gfs2_dinode); 236b3b94faaSDavid Teigland sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs; 237b3b94faaSDavid Teigland for (x = 2;; x++) { 238b3b94faaSDavid Teigland uint64_t space, d; 239b3b94faaSDavid Teigland uint32_t m; 240b3b94faaSDavid Teigland 241b3b94faaSDavid Teigland space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs; 242b3b94faaSDavid Teigland d = space; 243b3b94faaSDavid Teigland m = do_div(d, sdp->sd_inptrs); 244b3b94faaSDavid Teigland 245b3b94faaSDavid Teigland if (d != sdp->sd_jheightsize[x - 1] || m) 246b3b94faaSDavid Teigland break; 247b3b94faaSDavid Teigland sdp->sd_jheightsize[x] = space; 248b3b94faaSDavid Teigland } 249b3b94faaSDavid Teigland sdp->sd_max_jheight = x; 250b3b94faaSDavid Teigland gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); 251b3b94faaSDavid Teigland 252b3b94faaSDavid Teigland return 0; 253b3b94faaSDavid Teigland } 254b3b94faaSDavid Teigland 255b3b94faaSDavid Teigland int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *sb_gl) 256b3b94faaSDavid Teigland { 257b3b94faaSDavid Teigland return 0; 258b3b94faaSDavid Teigland } 259b3b94faaSDavid Teigland 260b3b94faaSDavid Teigland /** 261b3b94faaSDavid Teigland * gfs2_jindex_hold - Grab a lock on the jindex 262b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 263b3b94faaSDavid Teigland * @ji_gh: the holder for the jindex glock 264b3b94faaSDavid Teigland * 265b3b94faaSDavid Teigland * This is very similar to the gfs2_rindex_hold() function, except that 266b3b94faaSDavid Teigland * in general we hold the jindex lock for longer periods of time and 267b3b94faaSDavid Teigland * we grab it far less frequently (in general) then the rgrp lock. 268b3b94faaSDavid Teigland * 269b3b94faaSDavid Teigland * Returns: errno 270b3b94faaSDavid Teigland */ 271b3b94faaSDavid Teigland 272b3b94faaSDavid Teigland int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) 273b3b94faaSDavid Teigland { 274f42faf4fSSteven Whitehouse struct gfs2_inode *dip = get_v2ip(sdp->sd_jindex); 275b3b94faaSDavid Teigland struct qstr name; 276b3b94faaSDavid Teigland char buf[20]; 277b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 278b3b94faaSDavid Teigland int error; 279b3b94faaSDavid Teigland 280b3b94faaSDavid Teigland name.name = buf; 281b3b94faaSDavid Teigland 282b3b94faaSDavid Teigland down(&sdp->sd_jindex_mutex); 283b3b94faaSDavid Teigland 284b3b94faaSDavid Teigland for (;;) { 285b3b94faaSDavid Teigland error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 286b3b94faaSDavid Teigland GL_LOCAL_EXCL, ji_gh); 287b3b94faaSDavid Teigland if (error) 288b3b94faaSDavid Teigland break; 289b3b94faaSDavid Teigland 290b3b94faaSDavid Teigland name.len = sprintf(buf, "journal%u", sdp->sd_journals); 291b3b94faaSDavid Teigland 292f42faf4fSSteven Whitehouse error = gfs2_dir_search(get_v2ip(sdp->sd_jindex), &name, NULL, NULL); 293b3b94faaSDavid Teigland if (error == -ENOENT) { 294b3b94faaSDavid Teigland error = 0; 295b3b94faaSDavid Teigland break; 296b3b94faaSDavid Teigland } 297b3b94faaSDavid Teigland 298b3b94faaSDavid Teigland gfs2_glock_dq_uninit(ji_gh); 299b3b94faaSDavid Teigland 300b3b94faaSDavid Teigland if (error) 301b3b94faaSDavid Teigland break; 302b3b94faaSDavid Teigland 303b3b94faaSDavid Teigland error = -ENOMEM; 304b3b94faaSDavid Teigland jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL); 305b3b94faaSDavid Teigland if (!jd) 306b3b94faaSDavid Teigland break; 307b3b94faaSDavid Teigland 3087359a19cSSteven Whitehouse error = gfs2_lookupi(sdp->sd_jindex, &name, 1, &jd->jd_inode); 309b3b94faaSDavid Teigland if (error) { 310b3b94faaSDavid Teigland kfree(jd); 311b3b94faaSDavid Teigland break; 312b3b94faaSDavid Teigland } 313b3b94faaSDavid Teigland 314b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 315b3b94faaSDavid Teigland jd->jd_jid = sdp->sd_journals++; 316b3b94faaSDavid Teigland list_add_tail(&jd->jd_list, &sdp->sd_jindex_list); 317b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 318b3b94faaSDavid Teigland } 319b3b94faaSDavid Teigland 320b3b94faaSDavid Teigland up(&sdp->sd_jindex_mutex); 321b3b94faaSDavid Teigland 322b3b94faaSDavid Teigland return error; 323b3b94faaSDavid Teigland } 324b3b94faaSDavid Teigland 325b3b94faaSDavid Teigland /** 326b3b94faaSDavid Teigland * gfs2_jindex_free - Clear all the journal index information 327b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 328b3b94faaSDavid Teigland * 329b3b94faaSDavid Teigland */ 330b3b94faaSDavid Teigland 331b3b94faaSDavid Teigland void gfs2_jindex_free(struct gfs2_sbd *sdp) 332b3b94faaSDavid Teigland { 333b3b94faaSDavid Teigland struct list_head list; 334b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 335b3b94faaSDavid Teigland 336b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 337b3b94faaSDavid Teigland list_add(&list, &sdp->sd_jindex_list); 338b3b94faaSDavid Teigland list_del_init(&sdp->sd_jindex_list); 339b3b94faaSDavid Teigland sdp->sd_journals = 0; 340b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 341b3b94faaSDavid Teigland 342b3b94faaSDavid Teigland while (!list_empty(&list)) { 343b3b94faaSDavid Teigland jd = list_entry(list.next, struct gfs2_jdesc, jd_list); 344b3b94faaSDavid Teigland list_del(&jd->jd_list); 3457359a19cSSteven Whitehouse iput(jd->jd_inode); 346b3b94faaSDavid Teigland kfree(jd); 347b3b94faaSDavid Teigland } 348b3b94faaSDavid Teigland } 349b3b94faaSDavid Teigland 350b3b94faaSDavid Teigland static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid) 351b3b94faaSDavid Teigland { 352b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 353b3b94faaSDavid Teigland int found = 0; 354b3b94faaSDavid Teigland 355b3b94faaSDavid Teigland list_for_each_entry(jd, head, jd_list) { 356b3b94faaSDavid Teigland if (jd->jd_jid == jid) { 357b3b94faaSDavid Teigland found = 1; 358b3b94faaSDavid Teigland break; 359b3b94faaSDavid Teigland } 360b3b94faaSDavid Teigland } 361b3b94faaSDavid Teigland 362b3b94faaSDavid Teigland if (!found) 363b3b94faaSDavid Teigland jd = NULL; 364b3b94faaSDavid Teigland 365b3b94faaSDavid Teigland return jd; 366b3b94faaSDavid Teigland } 367b3b94faaSDavid Teigland 368b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid) 369b3b94faaSDavid Teigland { 370b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 371b3b94faaSDavid Teigland 372b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 373b3b94faaSDavid Teigland jd = jdesc_find_i(&sdp->sd_jindex_list, jid); 374b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 375b3b94faaSDavid Teigland 376b3b94faaSDavid Teigland return jd; 377b3b94faaSDavid Teigland } 378b3b94faaSDavid Teigland 379b3b94faaSDavid Teigland void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) 380b3b94faaSDavid Teigland { 381b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 382b3b94faaSDavid Teigland 383b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 384b3b94faaSDavid Teigland jd = jdesc_find_i(&sdp->sd_jindex_list, jid); 385b3b94faaSDavid Teigland if (jd) 386b3b94faaSDavid Teigland jd->jd_dirty = 1; 387b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 388b3b94faaSDavid Teigland } 389b3b94faaSDavid Teigland 390b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) 391b3b94faaSDavid Teigland { 392b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 393b3b94faaSDavid Teigland int found = 0; 394b3b94faaSDavid Teigland 395b3b94faaSDavid Teigland spin_lock(&sdp->sd_jindex_spin); 396b3b94faaSDavid Teigland 397b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 398b3b94faaSDavid Teigland if (jd->jd_dirty) { 399b3b94faaSDavid Teigland jd->jd_dirty = 0; 400b3b94faaSDavid Teigland found = 1; 401b3b94faaSDavid Teigland break; 402b3b94faaSDavid Teigland } 403b3b94faaSDavid Teigland } 404b3b94faaSDavid Teigland spin_unlock(&sdp->sd_jindex_spin); 405b3b94faaSDavid Teigland 406b3b94faaSDavid Teigland if (!found) 407b3b94faaSDavid Teigland jd = NULL; 408b3b94faaSDavid Teigland 409b3b94faaSDavid Teigland return jd; 410b3b94faaSDavid Teigland } 411b3b94faaSDavid Teigland 412b3b94faaSDavid Teigland int gfs2_jdesc_check(struct gfs2_jdesc *jd) 413b3b94faaSDavid Teigland { 4147359a19cSSteven Whitehouse struct gfs2_inode *ip = get_v2ip(jd->jd_inode); 415b3b94faaSDavid Teigland struct gfs2_sbd *sdp = ip->i_sbd; 416b3b94faaSDavid Teigland int ar; 417b3b94faaSDavid Teigland int error; 418b3b94faaSDavid Teigland 419b3b94faaSDavid Teigland if (ip->i_di.di_size < (8 << 20) || 420b3b94faaSDavid Teigland ip->i_di.di_size > (1 << 30) || 421b3b94faaSDavid Teigland (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) { 422b3b94faaSDavid Teigland gfs2_consist_inode(ip); 423b3b94faaSDavid Teigland return -EIO; 424b3b94faaSDavid Teigland } 425b3b94faaSDavid Teigland jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; 426b3b94faaSDavid Teigland 427b3b94faaSDavid Teigland error = gfs2_write_alloc_required(ip, 428b3b94faaSDavid Teigland 0, ip->i_di.di_size, 429b3b94faaSDavid Teigland &ar); 430b3b94faaSDavid Teigland if (!error && ar) { 431b3b94faaSDavid Teigland gfs2_consist_inode(ip); 432b3b94faaSDavid Teigland error = -EIO; 433b3b94faaSDavid Teigland } 434b3b94faaSDavid Teigland 435b3b94faaSDavid Teigland return error; 436b3b94faaSDavid Teigland } 437b3b94faaSDavid Teigland 438b3b94faaSDavid Teigland int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) 439b3b94faaSDavid Teigland { 440f42faf4fSSteven Whitehouse struct inode *inode = NULL; 441b3b94faaSDavid Teigland struct gfs2_glock *gl; 442b3b94faaSDavid Teigland int error; 443b3b94faaSDavid Teigland 444b3b94faaSDavid Teigland error = gfs2_glock_get(sdp, 445b3b94faaSDavid Teigland sdp->sd_sb.sb_master_dir.no_addr, 446b3b94faaSDavid Teigland &gfs2_inode_glops, CREATE, &gl); 447b3b94faaSDavid Teigland if (!error) { 448f42faf4fSSteven Whitehouse error = gfs2_lookup_simple(sdp->sd_root_dir, ".gfs2_admin", &inode); 449f42faf4fSSteven Whitehouse sdp->sd_master_dir = inode; 450b3b94faaSDavid Teigland gfs2_glock_put(gl); 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 { 4657359a19cSSteven Whitehouse struct gfs2_glock *j_gl = get_v2ip(sdp->sd_jdesc->jd_inode)->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 4757359a19cSSteven Whitehouse gfs2_meta_cache_flush(get_v2ip(sdp->sd_jdesc->jd_inode)); 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 { 553f42faf4fSSteven Whitehouse struct gfs2_inode *m_ip = get_v2ip(sdp->sd_statfs_inode); 554b3b94faaSDavid Teigland struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; 555f42faf4fSSteven Whitehouse struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); 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 { 602f42faf4fSSteven Whitehouse struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); 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 611b3b94faaSDavid Teigland down(&sdp->sd_statfs_mutex); 612d4e9c4c3SSteven Whitehouse gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); 613b3b94faaSDavid Teigland up(&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 { 628f42faf4fSSteven Whitehouse struct gfs2_inode *m_ip = get_v2ip(sdp->sd_statfs_inode); 629f42faf4fSSteven Whitehouse struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); 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 662b3b94faaSDavid Teigland down(&sdp->sd_statfs_mutex); 663d4e9c4c3SSteven Whitehouse gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); 664b3b94faaSDavid Teigland up(&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) 789b3b94faaSDavid Teigland error = statfs_slow_fill(get_gl2rgd(gh->gh_gl), sc); 790b3b94faaSDavid Teigland gfs2_glock_dq_uninit(gh); 791b3b94faaSDavid Teigland } 792b3b94faaSDavid Teigland } 793b3b94faaSDavid Teigland 794b3b94faaSDavid Teigland if (gh->gh_gl) 795b3b94faaSDavid Teigland done = 0; 796b3b94faaSDavid Teigland else if (rgd_next && !error) { 797b3b94faaSDavid Teigland error = gfs2_glock_nq_init(rgd_next->rd_gl, 798b3b94faaSDavid Teigland LM_ST_SHARED, 799b3b94faaSDavid Teigland GL_ASYNC, 800b3b94faaSDavid Teigland gh); 801b3b94faaSDavid Teigland rgd_next = gfs2_rgrpd_get_next(rgd_next); 802b3b94faaSDavid Teigland done = 0; 803b3b94faaSDavid Teigland } 804b3b94faaSDavid Teigland 805b3b94faaSDavid Teigland if (signal_pending(current)) 806b3b94faaSDavid Teigland error = -ERESTARTSYS; 807b3b94faaSDavid Teigland } 808b3b94faaSDavid Teigland 809b3b94faaSDavid Teigland if (done) 810b3b94faaSDavid Teigland break; 811b3b94faaSDavid Teigland 812b3b94faaSDavid Teigland yield(); 813b3b94faaSDavid Teigland } 814b3b94faaSDavid Teigland 815b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&ri_gh); 816b3b94faaSDavid Teigland 817b3b94faaSDavid Teigland out: 818b3b94faaSDavid Teigland kfree(gha); 819b3b94faaSDavid Teigland 820b3b94faaSDavid Teigland return error; 821b3b94faaSDavid Teigland } 822b3b94faaSDavid Teigland 823b3b94faaSDavid Teigland struct lfcc { 824b3b94faaSDavid Teigland struct list_head list; 825b3b94faaSDavid Teigland struct gfs2_holder gh; 826b3b94faaSDavid Teigland }; 827b3b94faaSDavid Teigland 828b3b94faaSDavid Teigland /** 829b3b94faaSDavid Teigland * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all 830b3b94faaSDavid Teigland * journals are clean 831b3b94faaSDavid Teigland * @sdp: the file system 832b3b94faaSDavid Teigland * @state: the state to put the transaction lock into 833b3b94faaSDavid Teigland * @t_gh: the hold on the transaction lock 834b3b94faaSDavid Teigland * 835b3b94faaSDavid Teigland * Returns: errno 836b3b94faaSDavid Teigland */ 837b3b94faaSDavid Teigland 838b3b94faaSDavid Teigland int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) 839b3b94faaSDavid Teigland { 840b3b94faaSDavid Teigland struct gfs2_holder ji_gh; 841b3b94faaSDavid Teigland struct gfs2_jdesc *jd; 842b3b94faaSDavid Teigland struct lfcc *lfcc; 843b3b94faaSDavid Teigland LIST_HEAD(list); 844b3b94faaSDavid Teigland struct gfs2_log_header lh; 845b3b94faaSDavid Teigland int error; 846b3b94faaSDavid Teigland 847b3b94faaSDavid Teigland error = gfs2_jindex_hold(sdp, &ji_gh); 848b3b94faaSDavid Teigland if (error) 849b3b94faaSDavid Teigland return error; 850b3b94faaSDavid Teigland 851b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 852b3b94faaSDavid Teigland lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL); 853b3b94faaSDavid Teigland if (!lfcc) { 854b3b94faaSDavid Teigland error = -ENOMEM; 855b3b94faaSDavid Teigland goto out; 856b3b94faaSDavid Teigland } 8577359a19cSSteven Whitehouse error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, LM_ST_SHARED, 0, 858b3b94faaSDavid Teigland &lfcc->gh); 859b3b94faaSDavid Teigland if (error) { 860b3b94faaSDavid Teigland kfree(lfcc); 861b3b94faaSDavid Teigland goto out; 862b3b94faaSDavid Teigland } 863b3b94faaSDavid Teigland list_add(&lfcc->list, &list); 864b3b94faaSDavid Teigland } 865b3b94faaSDavid Teigland 866b3b94faaSDavid Teigland error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED, 867b3b94faaSDavid Teigland LM_FLAG_PRIORITY | GL_NEVER_RECURSE | GL_NOCACHE, 868b3b94faaSDavid Teigland t_gh); 869b3b94faaSDavid Teigland 870b3b94faaSDavid Teigland list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { 871b3b94faaSDavid Teigland error = gfs2_jdesc_check(jd); 872b3b94faaSDavid Teigland if (error) 873b3b94faaSDavid Teigland break; 874b3b94faaSDavid Teigland error = gfs2_find_jhead(jd, &lh); 875b3b94faaSDavid Teigland if (error) 876b3b94faaSDavid Teigland break; 877b3b94faaSDavid Teigland if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { 878b3b94faaSDavid Teigland error = -EBUSY; 879b3b94faaSDavid Teigland break; 880b3b94faaSDavid Teigland } 881b3b94faaSDavid Teigland } 882b3b94faaSDavid Teigland 883b3b94faaSDavid Teigland if (error) 884b3b94faaSDavid Teigland gfs2_glock_dq_uninit(t_gh); 885b3b94faaSDavid Teigland 886b3b94faaSDavid Teigland out: 887b3b94faaSDavid Teigland while (!list_empty(&list)) { 888b3b94faaSDavid Teigland lfcc = list_entry(list.next, struct lfcc, list); 889b3b94faaSDavid Teigland list_del(&lfcc->list); 890b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&lfcc->gh); 891b3b94faaSDavid Teigland kfree(lfcc); 892b3b94faaSDavid Teigland } 893b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&ji_gh); 894b3b94faaSDavid Teigland 895b3b94faaSDavid Teigland return error; 896b3b94faaSDavid Teigland } 897b3b94faaSDavid Teigland 898b3b94faaSDavid Teigland /** 899b3b94faaSDavid Teigland * gfs2_freeze_fs - freezes the file system 900b3b94faaSDavid Teigland * @sdp: the file system 901b3b94faaSDavid Teigland * 902b3b94faaSDavid Teigland * This function flushes data and meta data for all machines by 903b3b94faaSDavid Teigland * aquiring the transaction log exclusively. All journals are 904b3b94faaSDavid Teigland * ensured to be in a clean state as well. 905b3b94faaSDavid Teigland * 906b3b94faaSDavid Teigland * Returns: errno 907b3b94faaSDavid Teigland */ 908b3b94faaSDavid Teigland 909b3b94faaSDavid Teigland int gfs2_freeze_fs(struct gfs2_sbd *sdp) 910b3b94faaSDavid Teigland { 911b3b94faaSDavid Teigland int error = 0; 912b3b94faaSDavid Teigland 913b3b94faaSDavid Teigland down(&sdp->sd_freeze_lock); 914b3b94faaSDavid Teigland 915b3b94faaSDavid Teigland if (!sdp->sd_freeze_count++) { 916b3b94faaSDavid Teigland error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh); 917b3b94faaSDavid Teigland if (error) 918b3b94faaSDavid Teigland sdp->sd_freeze_count--; 919b3b94faaSDavid Teigland } 920b3b94faaSDavid Teigland 921b3b94faaSDavid Teigland up(&sdp->sd_freeze_lock); 922b3b94faaSDavid Teigland 923b3b94faaSDavid Teigland return error; 924b3b94faaSDavid Teigland } 925b3b94faaSDavid Teigland 926b3b94faaSDavid Teigland /** 927b3b94faaSDavid Teigland * gfs2_unfreeze_fs - unfreezes the file system 928b3b94faaSDavid Teigland * @sdp: the file system 929b3b94faaSDavid Teigland * 930b3b94faaSDavid Teigland * This function allows the file system to proceed by unlocking 931b3b94faaSDavid Teigland * the exclusively held transaction lock. Other GFS2 nodes are 932b3b94faaSDavid Teigland * now free to acquire the lock shared and go on with their lives. 933b3b94faaSDavid Teigland * 934b3b94faaSDavid Teigland */ 935b3b94faaSDavid Teigland 936b3b94faaSDavid Teigland void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) 937b3b94faaSDavid Teigland { 938b3b94faaSDavid Teigland down(&sdp->sd_freeze_lock); 939b3b94faaSDavid Teigland 940b3b94faaSDavid Teigland if (sdp->sd_freeze_count && !--sdp->sd_freeze_count) 941b3b94faaSDavid Teigland gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); 942b3b94faaSDavid Teigland 943b3b94faaSDavid Teigland up(&sdp->sd_freeze_lock); 944b3b94faaSDavid Teigland } 945b3b94faaSDavid Teigland 946