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