xref: /openbmc/linux/fs/gfs2/super.c (revision 08bc2dbc)
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 /**
268b3b94faaSDavid Teigland  * gfs2_jindex_hold - Grab a lock on the jindex
269b3b94faaSDavid Teigland  * @sdp: The GFS2 superblock
270b3b94faaSDavid Teigland  * @ji_gh: the holder for the jindex glock
271b3b94faaSDavid Teigland  *
272b3b94faaSDavid Teigland  * This is very similar to the gfs2_rindex_hold() function, except that
273b3b94faaSDavid Teigland  * in general we hold the jindex lock for longer periods of time and
274b3b94faaSDavid Teigland  * we grab it far less frequently (in general) then the rgrp lock.
275b3b94faaSDavid Teigland  *
276b3b94faaSDavid Teigland  * Returns: errno
277b3b94faaSDavid Teigland  */
278b3b94faaSDavid Teigland 
279b3b94faaSDavid Teigland int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
280b3b94faaSDavid Teigland {
2815c676f6dSSteven Whitehouse 	struct gfs2_inode *dip = sdp->sd_jindex->u.generic_ip;
282b3b94faaSDavid Teigland 	struct qstr name;
283b3b94faaSDavid Teigland 	char buf[20];
284b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
285b3b94faaSDavid Teigland 	int error;
286b3b94faaSDavid Teigland 
287b3b94faaSDavid Teigland 	name.name = buf;
288b3b94faaSDavid Teigland 
289f55ab26aSSteven Whitehouse 	mutex_lock(&sdp->sd_jindex_mutex);
290b3b94faaSDavid Teigland 
291b3b94faaSDavid Teigland 	for (;;) {
292b3b94faaSDavid Teigland 		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
293b3b94faaSDavid Teigland 					   GL_LOCAL_EXCL, ji_gh);
294b3b94faaSDavid Teigland 		if (error)
295b3b94faaSDavid Teigland 			break;
296b3b94faaSDavid Teigland 
297b3b94faaSDavid Teigland 		name.len = sprintf(buf, "journal%u", sdp->sd_journals);
298c752666cSSteven Whitehouse 		name.hash = gfs2_disk_hash(name.name, name.len);
299b3b94faaSDavid Teigland 
300c752666cSSteven Whitehouse 		error = gfs2_dir_search(sdp->sd_jindex,
301568f4c96SSteven Whitehouse 					&name, NULL, NULL);
302b3b94faaSDavid Teigland 		if (error == -ENOENT) {
303b3b94faaSDavid Teigland 			error = 0;
304b3b94faaSDavid Teigland 			break;
305b3b94faaSDavid Teigland 		}
306b3b94faaSDavid Teigland 
307b3b94faaSDavid Teigland 		gfs2_glock_dq_uninit(ji_gh);
308b3b94faaSDavid Teigland 
309b3b94faaSDavid Teigland 		if (error)
310b3b94faaSDavid Teigland 			break;
311b3b94faaSDavid Teigland 
312b3b94faaSDavid Teigland 		error = -ENOMEM;
313b3b94faaSDavid Teigland 		jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL);
314b3b94faaSDavid Teigland 		if (!jd)
315b3b94faaSDavid Teigland 			break;
316b3b94faaSDavid Teigland 
317c752666cSSteven Whitehouse 		jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
318c752666cSSteven Whitehouse 		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
319c752666cSSteven Whitehouse 			if (!jd->jd_inode)
320c752666cSSteven Whitehouse 				error = -ENOENT;
321c752666cSSteven Whitehouse 			else
322c752666cSSteven Whitehouse 				error = PTR_ERR(jd->jd_inode);
323b3b94faaSDavid Teigland 			kfree(jd);
324b3b94faaSDavid Teigland 			break;
325b3b94faaSDavid Teigland 		}
326b3b94faaSDavid Teigland 
327b3b94faaSDavid Teigland 		spin_lock(&sdp->sd_jindex_spin);
328b3b94faaSDavid Teigland 		jd->jd_jid = sdp->sd_journals++;
329b3b94faaSDavid Teigland 		list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
330b3b94faaSDavid Teigland 		spin_unlock(&sdp->sd_jindex_spin);
331b3b94faaSDavid Teigland 	}
332b3b94faaSDavid Teigland 
333f55ab26aSSteven Whitehouse 	mutex_unlock(&sdp->sd_jindex_mutex);
334b3b94faaSDavid Teigland 
335b3b94faaSDavid Teigland 	return error;
336b3b94faaSDavid Teigland }
337b3b94faaSDavid Teigland 
338b3b94faaSDavid Teigland /**
339b3b94faaSDavid Teigland  * gfs2_jindex_free - Clear all the journal index information
340b3b94faaSDavid Teigland  * @sdp: The GFS2 superblock
341b3b94faaSDavid Teigland  *
342b3b94faaSDavid Teigland  */
343b3b94faaSDavid Teigland 
344b3b94faaSDavid Teigland void gfs2_jindex_free(struct gfs2_sbd *sdp)
345b3b94faaSDavid Teigland {
346b3b94faaSDavid Teigland 	struct list_head list;
347b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
348b3b94faaSDavid Teigland 
349b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_jindex_spin);
350b3b94faaSDavid Teigland 	list_add(&list, &sdp->sd_jindex_list);
351b3b94faaSDavid Teigland 	list_del_init(&sdp->sd_jindex_list);
352b3b94faaSDavid Teigland 	sdp->sd_journals = 0;
353b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_jindex_spin);
354b3b94faaSDavid Teigland 
355b3b94faaSDavid Teigland 	while (!list_empty(&list)) {
356b3b94faaSDavid Teigland 		jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
357b3b94faaSDavid Teigland 		list_del(&jd->jd_list);
3587359a19cSSteven Whitehouse 		iput(jd->jd_inode);
359b3b94faaSDavid Teigland 		kfree(jd);
360b3b94faaSDavid Teigland 	}
361b3b94faaSDavid Teigland }
362b3b94faaSDavid Teigland 
363b3b94faaSDavid Teigland static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid)
364b3b94faaSDavid Teigland {
365b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
366b3b94faaSDavid Teigland 	int found = 0;
367b3b94faaSDavid Teigland 
368b3b94faaSDavid Teigland 	list_for_each_entry(jd, head, jd_list) {
369b3b94faaSDavid Teigland 		if (jd->jd_jid == jid) {
370b3b94faaSDavid Teigland 			found = 1;
371b3b94faaSDavid Teigland 			break;
372b3b94faaSDavid Teigland 		}
373b3b94faaSDavid Teigland 	}
374b3b94faaSDavid Teigland 
375b3b94faaSDavid Teigland 	if (!found)
376b3b94faaSDavid Teigland 		jd = NULL;
377b3b94faaSDavid Teigland 
378b3b94faaSDavid Teigland 	return jd;
379b3b94faaSDavid Teigland }
380b3b94faaSDavid Teigland 
381b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid)
382b3b94faaSDavid Teigland {
383b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
384b3b94faaSDavid Teigland 
385b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_jindex_spin);
386b3b94faaSDavid Teigland 	jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
387b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_jindex_spin);
388b3b94faaSDavid Teigland 
389b3b94faaSDavid Teigland 	return jd;
390b3b94faaSDavid Teigland }
391b3b94faaSDavid Teigland 
392b3b94faaSDavid Teigland void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
393b3b94faaSDavid Teigland {
394b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
395b3b94faaSDavid Teigland 
396b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_jindex_spin);
397b3b94faaSDavid Teigland 	jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
398b3b94faaSDavid Teigland 	if (jd)
399b3b94faaSDavid Teigland 		jd->jd_dirty = 1;
400b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_jindex_spin);
401b3b94faaSDavid Teigland }
402b3b94faaSDavid Teigland 
403b3b94faaSDavid Teigland struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp)
404b3b94faaSDavid Teigland {
405b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
406b3b94faaSDavid Teigland 	int found = 0;
407b3b94faaSDavid Teigland 
408b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_jindex_spin);
409b3b94faaSDavid Teigland 
410b3b94faaSDavid Teigland 	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
411b3b94faaSDavid Teigland 		if (jd->jd_dirty) {
412b3b94faaSDavid Teigland 			jd->jd_dirty = 0;
413b3b94faaSDavid Teigland 			found = 1;
414b3b94faaSDavid Teigland 			break;
415b3b94faaSDavid Teigland 		}
416b3b94faaSDavid Teigland 	}
417b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_jindex_spin);
418b3b94faaSDavid Teigland 
419b3b94faaSDavid Teigland 	if (!found)
420b3b94faaSDavid Teigland 		jd = NULL;
421b3b94faaSDavid Teigland 
422b3b94faaSDavid Teigland 	return jd;
423b3b94faaSDavid Teigland }
424b3b94faaSDavid Teigland 
425b3b94faaSDavid Teigland int gfs2_jdesc_check(struct gfs2_jdesc *jd)
426b3b94faaSDavid Teigland {
4275c676f6dSSteven Whitehouse 	struct gfs2_inode *ip = jd->jd_inode->u.generic_ip;
428b3b94faaSDavid Teigland 	struct gfs2_sbd *sdp = ip->i_sbd;
429b3b94faaSDavid Teigland 	int ar;
430b3b94faaSDavid Teigland 	int error;
431b3b94faaSDavid Teigland 
432b3b94faaSDavid Teigland 	if (ip->i_di.di_size < (8 << 20) ||
433b3b94faaSDavid Teigland 	    ip->i_di.di_size > (1 << 30) ||
434b3b94faaSDavid Teigland 	    (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) {
435b3b94faaSDavid Teigland 		gfs2_consist_inode(ip);
436b3b94faaSDavid Teigland 		return -EIO;
437b3b94faaSDavid Teigland 	}
438b3b94faaSDavid Teigland 	jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
439b3b94faaSDavid Teigland 
440b3b94faaSDavid Teigland 	error = gfs2_write_alloc_required(ip,
441b3b94faaSDavid Teigland 					  0, ip->i_di.di_size,
442b3b94faaSDavid Teigland 					  &ar);
443b3b94faaSDavid Teigland 	if (!error && ar) {
444b3b94faaSDavid Teigland 		gfs2_consist_inode(ip);
445b3b94faaSDavid Teigland 		error = -EIO;
446b3b94faaSDavid Teigland 	}
447b3b94faaSDavid Teigland 
448b3b94faaSDavid Teigland 	return error;
449b3b94faaSDavid Teigland }
450b3b94faaSDavid Teigland 
451b3b94faaSDavid Teigland /**
452b3b94faaSDavid Teigland  * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
453b3b94faaSDavid Teigland  * @sdp: the filesystem
454b3b94faaSDavid Teigland  *
455b3b94faaSDavid Teigland  * Returns: errno
456b3b94faaSDavid Teigland  */
457b3b94faaSDavid Teigland 
458b3b94faaSDavid Teigland int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
459b3b94faaSDavid Teigland {
4605c676f6dSSteven Whitehouse 	struct gfs2_inode *ip = sdp->sd_jdesc->jd_inode->u.generic_ip;
4615c676f6dSSteven Whitehouse 	struct gfs2_glock *j_gl = ip->i_gl;
462b3b94faaSDavid Teigland 	struct gfs2_holder t_gh;
463b3b94faaSDavid Teigland 	struct gfs2_log_header head;
464b3b94faaSDavid Teigland 	int error;
465b3b94faaSDavid Teigland 
466b3b94faaSDavid Teigland 	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
467579b78a4SSteven Whitehouse 				   GL_LOCAL_EXCL, &t_gh);
468b3b94faaSDavid Teigland 	if (error)
469b3b94faaSDavid Teigland 		return error;
470b3b94faaSDavid Teigland 
4715c676f6dSSteven Whitehouse 	gfs2_meta_cache_flush(ip);
472b3b94faaSDavid Teigland 	j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
473b3b94faaSDavid Teigland 
474b3b94faaSDavid Teigland 	error = gfs2_find_jhead(sdp->sd_jdesc, &head);
475b3b94faaSDavid Teigland 	if (error)
476b3b94faaSDavid Teigland 		goto fail;
477b3b94faaSDavid Teigland 
478b3b94faaSDavid Teigland 	if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
479b3b94faaSDavid Teigland 		gfs2_consist(sdp);
480b3b94faaSDavid Teigland 		error = -EIO;
481b3b94faaSDavid Teigland 		goto fail;
482b3b94faaSDavid Teigland 	}
483b3b94faaSDavid Teigland 
484b3b94faaSDavid Teigland 	/*  Initialize some head of the log stuff  */
485b3b94faaSDavid Teigland 	sdp->sd_log_sequence = head.lh_sequence + 1;
486b3b94faaSDavid Teigland 	gfs2_log_pointers_init(sdp, head.lh_blkno);
487b3b94faaSDavid Teigland 
488b3b94faaSDavid Teigland 	error = gfs2_unlinked_init(sdp);
489b3b94faaSDavid Teigland 	if (error)
490b3b94faaSDavid Teigland 		goto fail;
491b3b94faaSDavid Teigland 	error = gfs2_quota_init(sdp);
492b3b94faaSDavid Teigland 	if (error)
493b3b94faaSDavid Teigland 		goto fail_unlinked;
494b3b94faaSDavid Teigland 
495b3b94faaSDavid Teigland 	set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
496b3b94faaSDavid Teigland 
497b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&t_gh);
498b3b94faaSDavid Teigland 
499b3b94faaSDavid Teigland 	return 0;
500b3b94faaSDavid Teigland 
501b3b94faaSDavid Teigland  fail_unlinked:
502b3b94faaSDavid Teigland 	gfs2_unlinked_cleanup(sdp);
503b3b94faaSDavid Teigland 
504b3b94faaSDavid Teigland  fail:
505b3b94faaSDavid Teigland 	t_gh.gh_flags |= GL_NOCACHE;
506b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&t_gh);
507b3b94faaSDavid Teigland 
508b3b94faaSDavid Teigland 	return error;
509b3b94faaSDavid Teigland }
510b3b94faaSDavid Teigland 
511b3b94faaSDavid Teigland /**
512b3b94faaSDavid Teigland  * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
513b3b94faaSDavid Teigland  * @sdp: the filesystem
514b3b94faaSDavid Teigland  *
515b3b94faaSDavid Teigland  * Returns: errno
516b3b94faaSDavid Teigland  */
517b3b94faaSDavid Teigland 
518b3b94faaSDavid Teigland int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
519b3b94faaSDavid Teigland {
520b3b94faaSDavid Teigland 	struct gfs2_holder t_gh;
521b3b94faaSDavid Teigland 	int error;
522b3b94faaSDavid Teigland 
523b3b94faaSDavid Teigland 	gfs2_unlinked_dealloc(sdp);
524b3b94faaSDavid Teigland 	gfs2_quota_sync(sdp);
525b3b94faaSDavid Teigland 	gfs2_statfs_sync(sdp);
526b3b94faaSDavid Teigland 
527b3b94faaSDavid Teigland 	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
528579b78a4SSteven Whitehouse 				GL_LOCAL_EXCL | GL_NOCACHE,
529b3b94faaSDavid Teigland 				&t_gh);
530b3b94faaSDavid Teigland 	if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
531b3b94faaSDavid Teigland 		return error;
532b3b94faaSDavid Teigland 
533b3b94faaSDavid Teigland 	gfs2_meta_syncfs(sdp);
534b3b94faaSDavid Teigland 	gfs2_log_shutdown(sdp);
535b3b94faaSDavid Teigland 
536b3b94faaSDavid Teigland 	clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
537b3b94faaSDavid Teigland 
538b3b94faaSDavid Teigland 	if (t_gh.gh_gl)
539b3b94faaSDavid Teigland 		gfs2_glock_dq_uninit(&t_gh);
540b3b94faaSDavid Teigland 
541b3b94faaSDavid Teigland 	gfs2_unlinked_cleanup(sdp);
542b3b94faaSDavid Teigland 	gfs2_quota_cleanup(sdp);
543b3b94faaSDavid Teigland 
544b3b94faaSDavid Teigland 	return error;
545b3b94faaSDavid Teigland }
546b3b94faaSDavid Teigland 
547b3b94faaSDavid Teigland int gfs2_statfs_init(struct gfs2_sbd *sdp)
548b3b94faaSDavid Teigland {
5495c676f6dSSteven Whitehouse 	struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip;
550b3b94faaSDavid Teigland 	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
5515c676f6dSSteven Whitehouse 	struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip;
552b3b94faaSDavid Teigland 	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
553b3b94faaSDavid Teigland 	struct buffer_head *m_bh, *l_bh;
554b3b94faaSDavid Teigland 	struct gfs2_holder gh;
555b3b94faaSDavid Teigland 	int error;
556b3b94faaSDavid Teigland 
557b3b94faaSDavid Teigland 	error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
558b3b94faaSDavid Teigland 				   &gh);
559b3b94faaSDavid Teigland 	if (error)
560b3b94faaSDavid Teigland 		return error;
561b3b94faaSDavid Teigland 
562b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(m_ip, &m_bh);
563b3b94faaSDavid Teigland 	if (error)
564b3b94faaSDavid Teigland 		goto out;
565b3b94faaSDavid Teigland 
566b3b94faaSDavid Teigland 	if (sdp->sd_args.ar_spectator) {
567b3b94faaSDavid Teigland 		spin_lock(&sdp->sd_statfs_spin);
568b3b94faaSDavid Teigland 		gfs2_statfs_change_in(m_sc, m_bh->b_data +
569b3b94faaSDavid Teigland 				      sizeof(struct gfs2_dinode));
570b3b94faaSDavid Teigland 		spin_unlock(&sdp->sd_statfs_spin);
571b3b94faaSDavid Teigland 	} else {
572b3b94faaSDavid Teigland 		error = gfs2_meta_inode_buffer(l_ip, &l_bh);
573b3b94faaSDavid Teigland 		if (error)
574b3b94faaSDavid Teigland 			goto out_m_bh;
575b3b94faaSDavid Teigland 
576b3b94faaSDavid Teigland 		spin_lock(&sdp->sd_statfs_spin);
577b3b94faaSDavid Teigland 		gfs2_statfs_change_in(m_sc, m_bh->b_data +
578b3b94faaSDavid Teigland 				      sizeof(struct gfs2_dinode));
579b3b94faaSDavid Teigland 		gfs2_statfs_change_in(l_sc, l_bh->b_data +
580b3b94faaSDavid Teigland 				      sizeof(struct gfs2_dinode));
581b3b94faaSDavid Teigland 		spin_unlock(&sdp->sd_statfs_spin);
582b3b94faaSDavid Teigland 
583b3b94faaSDavid Teigland 		brelse(l_bh);
584b3b94faaSDavid Teigland 	}
585b3b94faaSDavid Teigland 
586b3b94faaSDavid Teigland  out_m_bh:
587b3b94faaSDavid Teigland 	brelse(m_bh);
588b3b94faaSDavid Teigland 
589b3b94faaSDavid Teigland  out:
590b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&gh);
591b3b94faaSDavid Teigland 
592b3b94faaSDavid Teigland 	return 0;
593b3b94faaSDavid Teigland }
594b3b94faaSDavid Teigland 
595b3b94faaSDavid Teigland void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free,
596b3b94faaSDavid Teigland 			int64_t dinodes)
597b3b94faaSDavid Teigland {
5985c676f6dSSteven Whitehouse 	struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip;
599b3b94faaSDavid Teigland 	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
600b3b94faaSDavid Teigland 	struct buffer_head *l_bh;
601b3b94faaSDavid Teigland 	int error;
602b3b94faaSDavid Teigland 
603b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(l_ip, &l_bh);
604b3b94faaSDavid Teigland 	if (error)
605b3b94faaSDavid Teigland 		return;
606b3b94faaSDavid Teigland 
607f55ab26aSSteven Whitehouse 	mutex_lock(&sdp->sd_statfs_mutex);
608d4e9c4c3SSteven Whitehouse 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
609f55ab26aSSteven Whitehouse 	mutex_unlock(&sdp->sd_statfs_mutex);
610b3b94faaSDavid Teigland 
611b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_statfs_spin);
612b3b94faaSDavid Teigland 	l_sc->sc_total += total;
613b3b94faaSDavid Teigland 	l_sc->sc_free += free;
614b3b94faaSDavid Teigland 	l_sc->sc_dinodes += dinodes;
615b3b94faaSDavid Teigland 	gfs2_statfs_change_out(l_sc, l_bh->b_data +
616b3b94faaSDavid Teigland 			       sizeof(struct gfs2_dinode));
617b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_statfs_spin);
618b3b94faaSDavid Teigland 
619b3b94faaSDavid Teigland 	brelse(l_bh);
620b3b94faaSDavid Teigland }
621b3b94faaSDavid Teigland 
622b3b94faaSDavid Teigland int gfs2_statfs_sync(struct gfs2_sbd *sdp)
623b3b94faaSDavid Teigland {
6245c676f6dSSteven Whitehouse 	struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip;
6255c676f6dSSteven Whitehouse 	struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip;
626b3b94faaSDavid Teigland 	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
627b3b94faaSDavid Teigland 	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
628b3b94faaSDavid Teigland 	struct gfs2_holder gh;
629b3b94faaSDavid Teigland 	struct buffer_head *m_bh, *l_bh;
630b3b94faaSDavid Teigland 	int error;
631b3b94faaSDavid Teigland 
632b3b94faaSDavid Teigland 	error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
633b3b94faaSDavid Teigland 				   &gh);
634b3b94faaSDavid Teigland 	if (error)
635b3b94faaSDavid Teigland 		return error;
636b3b94faaSDavid Teigland 
637b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(m_ip, &m_bh);
638b3b94faaSDavid Teigland 	if (error)
639b3b94faaSDavid Teigland 		goto out;
640b3b94faaSDavid Teigland 
641b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_statfs_spin);
642b3b94faaSDavid Teigland 	gfs2_statfs_change_in(m_sc, m_bh->b_data +
643b3b94faaSDavid Teigland 			      sizeof(struct gfs2_dinode));
644b3b94faaSDavid Teigland 	if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) {
645b3b94faaSDavid Teigland 		spin_unlock(&sdp->sd_statfs_spin);
646b3b94faaSDavid Teigland 		goto out_bh;
647b3b94faaSDavid Teigland 	}
648b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_statfs_spin);
649b3b94faaSDavid Teigland 
650b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(l_ip, &l_bh);
651b3b94faaSDavid Teigland 	if (error)
652b3b94faaSDavid Teigland 		goto out_bh;
653b3b94faaSDavid Teigland 
654b3b94faaSDavid Teigland 	error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
655b3b94faaSDavid Teigland 	if (error)
656b3b94faaSDavid Teigland 		goto out_bh2;
657b3b94faaSDavid Teigland 
658f55ab26aSSteven Whitehouse 	mutex_lock(&sdp->sd_statfs_mutex);
659d4e9c4c3SSteven Whitehouse 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
660f55ab26aSSteven Whitehouse 	mutex_unlock(&sdp->sd_statfs_mutex);
661b3b94faaSDavid Teigland 
662b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_statfs_spin);
663b3b94faaSDavid Teigland 	m_sc->sc_total += l_sc->sc_total;
664b3b94faaSDavid Teigland 	m_sc->sc_free += l_sc->sc_free;
665b3b94faaSDavid Teigland 	m_sc->sc_dinodes += l_sc->sc_dinodes;
666b3b94faaSDavid Teigland 	memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
667b3b94faaSDavid Teigland 	memset(l_bh->b_data + sizeof(struct gfs2_dinode),
668b3b94faaSDavid Teigland 	       0, sizeof(struct gfs2_statfs_change));
669b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_statfs_spin);
670b3b94faaSDavid Teigland 
671d4e9c4c3SSteven Whitehouse 	gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
672b3b94faaSDavid Teigland 	gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
673b3b94faaSDavid Teigland 
674b3b94faaSDavid Teigland 	gfs2_trans_end(sdp);
675b3b94faaSDavid Teigland 
676b3b94faaSDavid Teigland  out_bh2:
677b3b94faaSDavid Teigland 	brelse(l_bh);
678b3b94faaSDavid Teigland 
679b3b94faaSDavid Teigland  out_bh:
680b3b94faaSDavid Teigland 	brelse(m_bh);
681b3b94faaSDavid Teigland 
682b3b94faaSDavid Teigland  out:
683b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&gh);
684b3b94faaSDavid Teigland 
685b3b94faaSDavid Teigland 	return error;
686b3b94faaSDavid Teigland }
687b3b94faaSDavid Teigland 
688b3b94faaSDavid Teigland /**
689b3b94faaSDavid Teigland  * gfs2_statfs_i - Do a statfs
690b3b94faaSDavid Teigland  * @sdp: the filesystem
691b3b94faaSDavid Teigland  * @sg: the sg structure
692b3b94faaSDavid Teigland  *
693b3b94faaSDavid Teigland  * Returns: errno
694b3b94faaSDavid Teigland  */
695b3b94faaSDavid Teigland 
696b3b94faaSDavid Teigland int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
697b3b94faaSDavid Teigland {
698b3b94faaSDavid Teigland 	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
699b3b94faaSDavid Teigland 	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
700b3b94faaSDavid Teigland 
701b3b94faaSDavid Teigland 	spin_lock(&sdp->sd_statfs_spin);
702b3b94faaSDavid Teigland 
703b3b94faaSDavid Teigland 	*sc = *m_sc;
704b3b94faaSDavid Teigland 	sc->sc_total += l_sc->sc_total;
705b3b94faaSDavid Teigland 	sc->sc_free += l_sc->sc_free;
706b3b94faaSDavid Teigland 	sc->sc_dinodes += l_sc->sc_dinodes;
707b3b94faaSDavid Teigland 
708b3b94faaSDavid Teigland 	spin_unlock(&sdp->sd_statfs_spin);
709b3b94faaSDavid Teigland 
710b3b94faaSDavid Teigland 	if (sc->sc_free < 0)
711b3b94faaSDavid Teigland 		sc->sc_free = 0;
712b3b94faaSDavid Teigland 	if (sc->sc_free > sc->sc_total)
713b3b94faaSDavid Teigland 		sc->sc_free = sc->sc_total;
714b3b94faaSDavid Teigland 	if (sc->sc_dinodes < 0)
715b3b94faaSDavid Teigland 		sc->sc_dinodes = 0;
716b3b94faaSDavid Teigland 
717b3b94faaSDavid Teigland 	return 0;
718b3b94faaSDavid Teigland }
719b3b94faaSDavid Teigland 
720b3b94faaSDavid Teigland /**
721b3b94faaSDavid Teigland  * statfs_fill - fill in the sg for a given RG
722b3b94faaSDavid Teigland  * @rgd: the RG
723b3b94faaSDavid Teigland  * @sc: the sc structure
724b3b94faaSDavid Teigland  *
725b3b94faaSDavid Teigland  * Returns: 0 on success, -ESTALE if the LVB is invalid
726b3b94faaSDavid Teigland  */
727b3b94faaSDavid Teigland 
728b3b94faaSDavid Teigland static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
729b3b94faaSDavid Teigland 			    struct gfs2_statfs_change *sc)
730b3b94faaSDavid Teigland {
731b3b94faaSDavid Teigland 	gfs2_rgrp_verify(rgd);
732b3b94faaSDavid Teigland 	sc->sc_total += rgd->rd_ri.ri_data;
733b3b94faaSDavid Teigland 	sc->sc_free += rgd->rd_rg.rg_free;
734b3b94faaSDavid Teigland 	sc->sc_dinodes += rgd->rd_rg.rg_dinodes;
735b3b94faaSDavid Teigland 	return 0;
736b3b94faaSDavid Teigland }
737b3b94faaSDavid Teigland 
738b3b94faaSDavid Teigland /**
739b3b94faaSDavid Teigland  * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
740b3b94faaSDavid Teigland  * @sdp: the filesystem
741b3b94faaSDavid Teigland  * @sc: the sc info that will be returned
742b3b94faaSDavid Teigland  *
743b3b94faaSDavid Teigland  * Any error (other than a signal) will cause this routine to fall back
744b3b94faaSDavid Teigland  * to the synchronous version.
745b3b94faaSDavid Teigland  *
746b3b94faaSDavid Teigland  * FIXME: This really shouldn't busy wait like this.
747b3b94faaSDavid Teigland  *
748b3b94faaSDavid Teigland  * Returns: errno
749b3b94faaSDavid Teigland  */
750b3b94faaSDavid Teigland 
751b3b94faaSDavid Teigland int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
752b3b94faaSDavid Teigland {
753b3b94faaSDavid Teigland 	struct gfs2_holder ri_gh;
754b3b94faaSDavid Teigland 	struct gfs2_rgrpd *rgd_next;
755b3b94faaSDavid Teigland 	struct gfs2_holder *gha, *gh;
756b3b94faaSDavid Teigland 	unsigned int slots = 64;
757b3b94faaSDavid Teigland 	unsigned int x;
758b3b94faaSDavid Teigland 	int done;
759b3b94faaSDavid Teigland 	int error = 0, err;
760b3b94faaSDavid Teigland 
761b3b94faaSDavid Teigland 	memset(sc, 0, sizeof(struct gfs2_statfs_change));
762b3b94faaSDavid Teigland 	gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
763b3b94faaSDavid Teigland 	if (!gha)
764b3b94faaSDavid Teigland 		return -ENOMEM;
765b3b94faaSDavid Teigland 
766b3b94faaSDavid Teigland 	error = gfs2_rindex_hold(sdp, &ri_gh);
767b3b94faaSDavid Teigland 	if (error)
768b3b94faaSDavid Teigland 		goto out;
769b3b94faaSDavid Teigland 
770b3b94faaSDavid Teigland 	rgd_next = gfs2_rgrpd_get_first(sdp);
771b3b94faaSDavid Teigland 
772b3b94faaSDavid Teigland 	for (;;) {
773b3b94faaSDavid Teigland 		done = 1;
774b3b94faaSDavid Teigland 
775b3b94faaSDavid Teigland 		for (x = 0; x < slots; x++) {
776b3b94faaSDavid Teigland 			gh = gha + x;
777b3b94faaSDavid Teigland 
778b3b94faaSDavid Teigland 			if (gh->gh_gl && gfs2_glock_poll(gh)) {
779b3b94faaSDavid Teigland 				err = gfs2_glock_wait(gh);
780b3b94faaSDavid Teigland 				if (err) {
781b3b94faaSDavid Teigland 					gfs2_holder_uninit(gh);
782b3b94faaSDavid Teigland 					error = err;
783b3b94faaSDavid Teigland 				} else {
784b3b94faaSDavid Teigland 					if (!error)
7855c676f6dSSteven Whitehouse 						error = statfs_slow_fill(
7865c676f6dSSteven Whitehouse 							gh->gh_gl->gl_object, sc);
787b3b94faaSDavid Teigland 					gfs2_glock_dq_uninit(gh);
788b3b94faaSDavid Teigland 				}
789b3b94faaSDavid Teigland 			}
790b3b94faaSDavid Teigland 
791b3b94faaSDavid Teigland 			if (gh->gh_gl)
792b3b94faaSDavid Teigland 				done = 0;
793b3b94faaSDavid Teigland 			else if (rgd_next && !error) {
794b3b94faaSDavid Teigland 				error = gfs2_glock_nq_init(rgd_next->rd_gl,
795b3b94faaSDavid Teigland 							   LM_ST_SHARED,
796b3b94faaSDavid Teigland 							   GL_ASYNC,
797b3b94faaSDavid Teigland 							   gh);
798b3b94faaSDavid Teigland 				rgd_next = gfs2_rgrpd_get_next(rgd_next);
799b3b94faaSDavid Teigland 				done = 0;
800b3b94faaSDavid Teigland 			}
801b3b94faaSDavid Teigland 
802b3b94faaSDavid Teigland 			if (signal_pending(current))
803b3b94faaSDavid Teigland 				error = -ERESTARTSYS;
804b3b94faaSDavid Teigland 		}
805b3b94faaSDavid Teigland 
806b3b94faaSDavid Teigland 		if (done)
807b3b94faaSDavid Teigland 			break;
808b3b94faaSDavid Teigland 
809b3b94faaSDavid Teigland 		yield();
810b3b94faaSDavid Teigland 	}
811b3b94faaSDavid Teigland 
812b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&ri_gh);
813b3b94faaSDavid Teigland 
814b3b94faaSDavid Teigland  out:
815b3b94faaSDavid Teigland 	kfree(gha);
816b3b94faaSDavid Teigland 
817b3b94faaSDavid Teigland 	return error;
818b3b94faaSDavid Teigland }
819b3b94faaSDavid Teigland 
820b3b94faaSDavid Teigland struct lfcc {
821b3b94faaSDavid Teigland 	struct list_head list;
822b3b94faaSDavid Teigland 	struct gfs2_holder gh;
823b3b94faaSDavid Teigland };
824b3b94faaSDavid Teigland 
825b3b94faaSDavid Teigland /**
826b3b94faaSDavid Teigland  * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all
827b3b94faaSDavid Teigland  *                            journals are clean
828b3b94faaSDavid Teigland  * @sdp: the file system
829b3b94faaSDavid Teigland  * @state: the state to put the transaction lock into
830b3b94faaSDavid Teigland  * @t_gh: the hold on the transaction lock
831b3b94faaSDavid Teigland  *
832b3b94faaSDavid Teigland  * Returns: errno
833b3b94faaSDavid Teigland  */
834b3b94faaSDavid Teigland 
83508bc2dbcSAdrian Bunk static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
83608bc2dbcSAdrian Bunk 				    struct gfs2_holder *t_gh)
837b3b94faaSDavid Teigland {
8385c676f6dSSteven Whitehouse 	struct gfs2_inode *ip;
839b3b94faaSDavid Teigland 	struct gfs2_holder ji_gh;
840b3b94faaSDavid Teigland 	struct gfs2_jdesc *jd;
841b3b94faaSDavid Teigland 	struct lfcc *lfcc;
842b3b94faaSDavid Teigland 	LIST_HEAD(list);
843b3b94faaSDavid Teigland 	struct gfs2_log_header lh;
844b3b94faaSDavid Teigland 	int error;
845b3b94faaSDavid Teigland 
846b3b94faaSDavid Teigland 	error = gfs2_jindex_hold(sdp, &ji_gh);
847b3b94faaSDavid Teigland 	if (error)
848b3b94faaSDavid Teigland 		return error;
849b3b94faaSDavid Teigland 
850b3b94faaSDavid Teigland 	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
851b3b94faaSDavid Teigland 		lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
852b3b94faaSDavid Teigland 		if (!lfcc) {
853b3b94faaSDavid Teigland 			error = -ENOMEM;
854b3b94faaSDavid Teigland 			goto out;
855b3b94faaSDavid Teigland 		}
8565c676f6dSSteven Whitehouse 		ip = jd->jd_inode->u.generic_ip;
8575c676f6dSSteven Whitehouse 		error = gfs2_glock_nq_init(ip->i_gl,
858568f4c96SSteven Whitehouse 					   LM_ST_SHARED, 0,
859b3b94faaSDavid Teigland 					   &lfcc->gh);
860b3b94faaSDavid Teigland 		if (error) {
861b3b94faaSDavid Teigland 			kfree(lfcc);
862b3b94faaSDavid Teigland 			goto out;
863b3b94faaSDavid Teigland 		}
864b3b94faaSDavid Teigland 		list_add(&lfcc->list, &list);
865b3b94faaSDavid Teigland 	}
866b3b94faaSDavid Teigland 
867b3b94faaSDavid Teigland 	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED,
868579b78a4SSteven Whitehouse 			       LM_FLAG_PRIORITY | GL_NOCACHE,
869b3b94faaSDavid Teigland 			       t_gh);
870b3b94faaSDavid Teigland 
871b3b94faaSDavid Teigland 	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
872b3b94faaSDavid Teigland 		error = gfs2_jdesc_check(jd);
873b3b94faaSDavid Teigland 		if (error)
874b3b94faaSDavid Teigland 			break;
875b3b94faaSDavid Teigland 		error = gfs2_find_jhead(jd, &lh);
876b3b94faaSDavid Teigland 		if (error)
877b3b94faaSDavid Teigland 			break;
878b3b94faaSDavid Teigland 		if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
879b3b94faaSDavid Teigland 			error = -EBUSY;
880b3b94faaSDavid Teigland 			break;
881b3b94faaSDavid Teigland 		}
882b3b94faaSDavid Teigland 	}
883b3b94faaSDavid Teigland 
884b3b94faaSDavid Teigland 	if (error)
885b3b94faaSDavid Teigland 		gfs2_glock_dq_uninit(t_gh);
886b3b94faaSDavid Teigland 
887b3b94faaSDavid Teigland  out:
888b3b94faaSDavid Teigland 	while (!list_empty(&list)) {
889b3b94faaSDavid Teigland 		lfcc = list_entry(list.next, struct lfcc, list);
890b3b94faaSDavid Teigland 		list_del(&lfcc->list);
891b3b94faaSDavid Teigland 		gfs2_glock_dq_uninit(&lfcc->gh);
892b3b94faaSDavid Teigland 		kfree(lfcc);
893b3b94faaSDavid Teigland 	}
894b3b94faaSDavid Teigland 	gfs2_glock_dq_uninit(&ji_gh);
895b3b94faaSDavid Teigland 
896b3b94faaSDavid Teigland 	return error;
897b3b94faaSDavid Teigland }
898b3b94faaSDavid Teigland 
899b3b94faaSDavid Teigland /**
900b3b94faaSDavid Teigland  * gfs2_freeze_fs - freezes the file system
901b3b94faaSDavid Teigland  * @sdp: the file system
902b3b94faaSDavid Teigland  *
903b3b94faaSDavid Teigland  * This function flushes data and meta data for all machines by
904b3b94faaSDavid Teigland  * aquiring the transaction log exclusively.  All journals are
905b3b94faaSDavid Teigland  * ensured to be in a clean state as well.
906b3b94faaSDavid Teigland  *
907b3b94faaSDavid Teigland  * Returns: errno
908b3b94faaSDavid Teigland  */
909b3b94faaSDavid Teigland 
910b3b94faaSDavid Teigland int gfs2_freeze_fs(struct gfs2_sbd *sdp)
911b3b94faaSDavid Teigland {
912b3b94faaSDavid Teigland 	int error = 0;
913b3b94faaSDavid Teigland 
914f55ab26aSSteven Whitehouse 	mutex_lock(&sdp->sd_freeze_lock);
915b3b94faaSDavid Teigland 
916b3b94faaSDavid Teigland 	if (!sdp->sd_freeze_count++) {
917b3b94faaSDavid Teigland 		error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
918b3b94faaSDavid Teigland 		if (error)
919b3b94faaSDavid Teigland 			sdp->sd_freeze_count--;
920b3b94faaSDavid Teigland 	}
921b3b94faaSDavid Teigland 
922f55ab26aSSteven Whitehouse 	mutex_unlock(&sdp->sd_freeze_lock);
923b3b94faaSDavid Teigland 
924b3b94faaSDavid Teigland 	return error;
925b3b94faaSDavid Teigland }
926b3b94faaSDavid Teigland 
927b3b94faaSDavid Teigland /**
928b3b94faaSDavid Teigland  * gfs2_unfreeze_fs - unfreezes the file system
929b3b94faaSDavid Teigland  * @sdp: the file system
930b3b94faaSDavid Teigland  *
931b3b94faaSDavid Teigland  * This function allows the file system to proceed by unlocking
932b3b94faaSDavid Teigland  * the exclusively held transaction lock.  Other GFS2 nodes are
933b3b94faaSDavid Teigland  * now free to acquire the lock shared and go on with their lives.
934b3b94faaSDavid Teigland  *
935b3b94faaSDavid Teigland  */
936b3b94faaSDavid Teigland 
937b3b94faaSDavid Teigland void gfs2_unfreeze_fs(struct gfs2_sbd *sdp)
938b3b94faaSDavid Teigland {
939f55ab26aSSteven Whitehouse 	mutex_lock(&sdp->sd_freeze_lock);
940b3b94faaSDavid Teigland 
941b3b94faaSDavid Teigland 	if (sdp->sd_freeze_count && !--sdp->sd_freeze_count)
942b3b94faaSDavid Teigland 		gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
943b3b94faaSDavid Teigland 
944f55ab26aSSteven Whitehouse 	mutex_unlock(&sdp->sd_freeze_lock);
945b3b94faaSDavid Teigland }
946b3b94faaSDavid Teigland 
947