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