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