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