diff options
Diffstat (limited to 'fs/gfs2/ops_super.c')
-rw-r--r-- | fs/gfs2/ops_super.c | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c new file mode 100644 index 00000000000..5f5fc3c4290 --- /dev/null +++ b/fs/gfs2/ops_super.c | |||
@@ -0,0 +1,471 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License v.2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/completion.h> | ||
14 | #include <linux/buffer_head.h> | ||
15 | #include <linux/statfs.h> | ||
16 | #include <linux/vmalloc.h> | ||
17 | #include <linux/seq_file.h> | ||
18 | #include <linux/mount.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/gfs2_ondisk.h> | ||
22 | #include <linux/crc32.h> | ||
23 | |||
24 | #include "gfs2.h" | ||
25 | #include "lm_interface.h" | ||
26 | #include "incore.h" | ||
27 | #include "glock.h" | ||
28 | #include "inode.h" | ||
29 | #include "lm.h" | ||
30 | #include "log.h" | ||
31 | #include "mount.h" | ||
32 | #include "ops_super.h" | ||
33 | #include "page.h" | ||
34 | #include "quota.h" | ||
35 | #include "recovery.h" | ||
36 | #include "rgrp.h" | ||
37 | #include "super.h" | ||
38 | #include "sys.h" | ||
39 | #include "util.h" | ||
40 | #include "trans.h" | ||
41 | #include "dir.h" | ||
42 | #include "eattr.h" | ||
43 | #include "bmap.h" | ||
44 | |||
45 | /** | ||
46 | * gfs2_write_inode - Make sure the inode is stable on the disk | ||
47 | * @inode: The inode | ||
48 | * @sync: synchronous write flag | ||
49 | * | ||
50 | * Returns: errno | ||
51 | */ | ||
52 | |||
53 | static int gfs2_write_inode(struct inode *inode, int sync) | ||
54 | { | ||
55 | struct gfs2_inode *ip = GFS2_I(inode); | ||
56 | |||
57 | /* Check this is a "normal" inode */ | ||
58 | if (inode->u.generic_ip) { | ||
59 | if (current->flags & PF_MEMALLOC) | ||
60 | return 0; | ||
61 | if (sync) | ||
62 | gfs2_log_flush(GFS2_SB(inode), ip->i_gl); | ||
63 | } | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * gfs2_put_super - Unmount the filesystem | ||
70 | * @sb: The VFS superblock | ||
71 | * | ||
72 | */ | ||
73 | |||
74 | static void gfs2_put_super(struct super_block *sb) | ||
75 | { | ||
76 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
77 | int error; | ||
78 | |||
79 | if (!sdp) | ||
80 | return; | ||
81 | |||
82 | /* Unfreeze the filesystem, if we need to */ | ||
83 | |||
84 | mutex_lock(&sdp->sd_freeze_lock); | ||
85 | if (sdp->sd_freeze_count) | ||
86 | gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); | ||
87 | mutex_unlock(&sdp->sd_freeze_lock); | ||
88 | |||
89 | kthread_stop(sdp->sd_quotad_process); | ||
90 | kthread_stop(sdp->sd_logd_process); | ||
91 | kthread_stop(sdp->sd_recoverd_process); | ||
92 | while (sdp->sd_glockd_num--) | ||
93 | kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); | ||
94 | kthread_stop(sdp->sd_scand_process); | ||
95 | |||
96 | if (!(sb->s_flags & MS_RDONLY)) { | ||
97 | error = gfs2_make_fs_ro(sdp); | ||
98 | if (error) | ||
99 | gfs2_io_error(sdp); | ||
100 | } | ||
101 | /* At this point, we're through modifying the disk */ | ||
102 | |||
103 | /* Release stuff */ | ||
104 | |||
105 | iput(sdp->sd_master_dir); | ||
106 | iput(sdp->sd_jindex); | ||
107 | iput(sdp->sd_inum_inode); | ||
108 | iput(sdp->sd_statfs_inode); | ||
109 | iput(sdp->sd_rindex); | ||
110 | iput(sdp->sd_quota_inode); | ||
111 | |||
112 | gfs2_glock_put(sdp->sd_rename_gl); | ||
113 | gfs2_glock_put(sdp->sd_trans_gl); | ||
114 | |||
115 | if (!sdp->sd_args.ar_spectator) { | ||
116 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); | ||
117 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | ||
118 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
119 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | ||
120 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | ||
121 | iput(sdp->sd_ir_inode); | ||
122 | iput(sdp->sd_sc_inode); | ||
123 | iput(sdp->sd_qc_inode); | ||
124 | } | ||
125 | |||
126 | gfs2_glock_dq_uninit(&sdp->sd_live_gh); | ||
127 | gfs2_clear_rgrpd(sdp); | ||
128 | gfs2_jindex_free(sdp); | ||
129 | /* Take apart glock structures and buffer lists */ | ||
130 | gfs2_gl_hash_clear(sdp, WAIT); | ||
131 | /* Unmount the locking protocol */ | ||
132 | gfs2_lm_unmount(sdp); | ||
133 | |||
134 | /* At this point, we're through participating in the lockspace */ | ||
135 | gfs2_sys_fs_del(sdp); | ||
136 | vfree(sdp); | ||
137 | sb->s_fs_info = NULL; | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * gfs2_write_super - disk commit all incore transactions | ||
142 | * @sb: the filesystem | ||
143 | * | ||
144 | * This function is called every time sync(2) is called. | ||
145 | * After this exits, all dirty buffers are synced. | ||
146 | */ | ||
147 | |||
148 | static void gfs2_write_super(struct super_block *sb) | ||
149 | { | ||
150 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
151 | gfs2_log_flush(sdp, NULL); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * gfs2_write_super_lockfs - prevent further writes to the filesystem | ||
156 | * @sb: the VFS structure for the filesystem | ||
157 | * | ||
158 | */ | ||
159 | |||
160 | static void gfs2_write_super_lockfs(struct super_block *sb) | ||
161 | { | ||
162 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
163 | int error; | ||
164 | |||
165 | for (;;) { | ||
166 | error = gfs2_freeze_fs(sdp); | ||
167 | if (!error) | ||
168 | break; | ||
169 | |||
170 | switch (error) { | ||
171 | case -EBUSY: | ||
172 | fs_err(sdp, "waiting for recovery before freeze\n"); | ||
173 | break; | ||
174 | |||
175 | default: | ||
176 | fs_err(sdp, "error freezing FS: %d\n", error); | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | fs_err(sdp, "retrying...\n"); | ||
181 | msleep(1000); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * gfs2_unlockfs - reallow writes to the filesystem | ||
187 | * @sb: the VFS structure for the filesystem | ||
188 | * | ||
189 | */ | ||
190 | |||
191 | static void gfs2_unlockfs(struct super_block *sb) | ||
192 | { | ||
193 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
194 | gfs2_unfreeze_fs(sdp); | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * gfs2_statfs - Gather and return stats about the filesystem | ||
199 | * @sb: The superblock | ||
200 | * @statfsbuf: The buffer | ||
201 | * | ||
202 | * Returns: 0 on success or error code | ||
203 | */ | ||
204 | |||
205 | static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) | ||
206 | { | ||
207 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
208 | struct gfs2_statfs_change sc; | ||
209 | int error; | ||
210 | |||
211 | if (gfs2_tune_get(sdp, gt_statfs_slow)) | ||
212 | error = gfs2_statfs_slow(sdp, &sc); | ||
213 | else | ||
214 | error = gfs2_statfs_i(sdp, &sc); | ||
215 | |||
216 | if (error) | ||
217 | return error; | ||
218 | |||
219 | memset(buf, 0, sizeof(struct kstatfs)); | ||
220 | |||
221 | buf->f_type = GFS2_MAGIC; | ||
222 | buf->f_bsize = sdp->sd_sb.sb_bsize; | ||
223 | buf->f_blocks = sc.sc_total; | ||
224 | buf->f_bfree = sc.sc_free; | ||
225 | buf->f_bavail = sc.sc_free; | ||
226 | buf->f_files = sc.sc_dinodes + sc.sc_free; | ||
227 | buf->f_ffree = sc.sc_free; | ||
228 | buf->f_namelen = GFS2_FNAMESIZE; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * gfs2_remount_fs - called when the FS is remounted | ||
235 | * @sb: the filesystem | ||
236 | * @flags: the remount flags | ||
237 | * @data: extra data passed in (not used right now) | ||
238 | * | ||
239 | * Returns: errno | ||
240 | */ | ||
241 | |||
242 | static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | ||
243 | { | ||
244 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
245 | int error; | ||
246 | |||
247 | error = gfs2_mount_args(sdp, data, 1); | ||
248 | if (error) | ||
249 | return error; | ||
250 | |||
251 | if (sdp->sd_args.ar_spectator) | ||
252 | *flags |= MS_RDONLY; | ||
253 | else { | ||
254 | if (*flags & MS_RDONLY) { | ||
255 | if (!(sb->s_flags & MS_RDONLY)) | ||
256 | error = gfs2_make_fs_ro(sdp); | ||
257 | } else if (!(*flags & MS_RDONLY) && | ||
258 | (sb->s_flags & MS_RDONLY)) { | ||
259 | error = gfs2_make_fs_rw(sdp); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (*flags & (MS_NOATIME | MS_NODIRATIME)) | ||
264 | set_bit(SDF_NOATIME, &sdp->sd_flags); | ||
265 | else | ||
266 | clear_bit(SDF_NOATIME, &sdp->sd_flags); | ||
267 | |||
268 | /* Don't let the VFS update atimes. GFS2 handles this itself. */ | ||
269 | *flags |= MS_NOATIME | MS_NODIRATIME; | ||
270 | |||
271 | return error; | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * gfs2_clear_inode - Deallocate an inode when VFS is done with it | ||
276 | * @inode: The VFS inode | ||
277 | * | ||
278 | */ | ||
279 | |||
280 | static void gfs2_clear_inode(struct inode *inode) | ||
281 | { | ||
282 | /* This tells us its a "real" inode and not one which only | ||
283 | * serves to contain an address space (see rgrp.c, meta_io.c) | ||
284 | * which therefore doesn't have its own glocks. | ||
285 | */ | ||
286 | if (inode->u.generic_ip) { | ||
287 | struct gfs2_inode *ip = GFS2_I(inode); | ||
288 | gfs2_glock_inode_squish(inode); | ||
289 | gfs2_assert(inode->i_sb->s_fs_info, ip->i_gl->gl_state == LM_ST_UNLOCKED); | ||
290 | ip->i_gl->gl_object = NULL; | ||
291 | gfs2_glock_schedule_for_reclaim(ip->i_gl); | ||
292 | gfs2_glock_put(ip->i_gl); | ||
293 | ip->i_gl = NULL; | ||
294 | if (ip->i_iopen_gh.gh_gl) | ||
295 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * gfs2_show_options - Show mount options for /proc/mounts | ||
301 | * @s: seq_file structure | ||
302 | * @mnt: vfsmount | ||
303 | * | ||
304 | * Returns: 0 on success or error code | ||
305 | */ | ||
306 | |||
307 | static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | ||
308 | { | ||
309 | struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; | ||
310 | struct gfs2_args *args = &sdp->sd_args; | ||
311 | |||
312 | if (args->ar_lockproto[0]) | ||
313 | seq_printf(s, ",lockproto=%s", args->ar_lockproto); | ||
314 | if (args->ar_locktable[0]) | ||
315 | seq_printf(s, ",locktable=%s", args->ar_locktable); | ||
316 | if (args->ar_hostdata[0]) | ||
317 | seq_printf(s, ",hostdata=%s", args->ar_hostdata); | ||
318 | if (args->ar_spectator) | ||
319 | seq_printf(s, ",spectator"); | ||
320 | if (args->ar_ignore_local_fs) | ||
321 | seq_printf(s, ",ignore_local_fs"); | ||
322 | if (args->ar_localflocks) | ||
323 | seq_printf(s, ",localflocks"); | ||
324 | if (args->ar_localcaching) | ||
325 | seq_printf(s, ",localcaching"); | ||
326 | if (args->ar_debug) | ||
327 | seq_printf(s, ",debug"); | ||
328 | if (args->ar_upgrade) | ||
329 | seq_printf(s, ",upgrade"); | ||
330 | if (args->ar_num_glockd != GFS2_GLOCKD_DEFAULT) | ||
331 | seq_printf(s, ",num_glockd=%u", args->ar_num_glockd); | ||
332 | if (args->ar_posix_acl) | ||
333 | seq_printf(s, ",acl"); | ||
334 | if (args->ar_quota != GFS2_QUOTA_DEFAULT) { | ||
335 | char *state; | ||
336 | switch (args->ar_quota) { | ||
337 | case GFS2_QUOTA_OFF: | ||
338 | state = "off"; | ||
339 | break; | ||
340 | case GFS2_QUOTA_ACCOUNT: | ||
341 | state = "account"; | ||
342 | break; | ||
343 | case GFS2_QUOTA_ON: | ||
344 | state = "on"; | ||
345 | break; | ||
346 | default: | ||
347 | state = "unknown"; | ||
348 | break; | ||
349 | } | ||
350 | seq_printf(s, ",quota=%s", state); | ||
351 | } | ||
352 | if (args->ar_suiddir) | ||
353 | seq_printf(s, ",suiddir"); | ||
354 | if (args->ar_data != GFS2_DATA_DEFAULT) { | ||
355 | char *state; | ||
356 | switch (args->ar_data) { | ||
357 | case GFS2_DATA_WRITEBACK: | ||
358 | state = "writeback"; | ||
359 | break; | ||
360 | case GFS2_DATA_ORDERED: | ||
361 | state = "ordered"; | ||
362 | break; | ||
363 | default: | ||
364 | state = "unknown"; | ||
365 | break; | ||
366 | } | ||
367 | seq_printf(s, ",data=%s", state); | ||
368 | } | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * We have to (at the moment) hold the inodes main lock to cover | ||
375 | * the gap between unlocking the shared lock on the iopen lock and | ||
376 | * taking the exclusive lock. I'd rather do a shared -> exclusive | ||
377 | * conversion on the iopen lock, but we can change that later. This | ||
378 | * is safe, just less efficient. | ||
379 | */ | ||
380 | static void gfs2_delete_inode(struct inode *inode) | ||
381 | { | ||
382 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
383 | struct gfs2_inode *ip = GFS2_I(inode); | ||
384 | struct gfs2_holder gh; | ||
385 | int error; | ||
386 | |||
387 | if (!inode->u.generic_ip) | ||
388 | goto out; | ||
389 | |||
390 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh); | ||
391 | if (unlikely(error)) { | ||
392 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
393 | goto out; | ||
394 | } | ||
395 | |||
396 | gfs2_glock_dq(&ip->i_iopen_gh); | ||
397 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); | ||
398 | error = gfs2_glock_nq(&ip->i_iopen_gh); | ||
399 | if (error) | ||
400 | goto out_uninit; | ||
401 | |||
402 | if (S_ISDIR(ip->i_di.di_mode) && | ||
403 | (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { | ||
404 | error = gfs2_dir_exhash_dealloc(ip); | ||
405 | if (error) | ||
406 | goto out_unlock; | ||
407 | } | ||
408 | |||
409 | if (ip->i_di.di_eattr) { | ||
410 | error = gfs2_ea_dealloc(ip); | ||
411 | if (error) | ||
412 | goto out_unlock; | ||
413 | } | ||
414 | |||
415 | if (!gfs2_is_stuffed(ip)) { | ||
416 | error = gfs2_file_dealloc(ip); | ||
417 | if (error) | ||
418 | goto out_unlock; | ||
419 | } | ||
420 | |||
421 | error = gfs2_dinode_dealloc(ip); | ||
422 | |||
423 | out_unlock: | ||
424 | gfs2_glock_dq(&ip->i_iopen_gh); | ||
425 | out_uninit: | ||
426 | gfs2_holder_uninit(&ip->i_iopen_gh); | ||
427 | gfs2_glock_dq_uninit(&gh); | ||
428 | if (error) | ||
429 | fs_warn(sdp, "gfs2_delete_inode: %d\n", error); | ||
430 | out: | ||
431 | truncate_inode_pages(&inode->i_data, 0); | ||
432 | clear_inode(inode); | ||
433 | } | ||
434 | |||
435 | |||
436 | |||
437 | static struct inode *gfs2_alloc_inode(struct super_block *sb) | ||
438 | { | ||
439 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
440 | struct gfs2_inode *ip; | ||
441 | |||
442 | ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); | ||
443 | if (ip) { | ||
444 | ip->i_flags = 0; | ||
445 | ip->i_gl = NULL; | ||
446 | ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); | ||
447 | ip->i_last_pfault = jiffies; | ||
448 | } | ||
449 | return &ip->i_inode; | ||
450 | } | ||
451 | |||
452 | static void gfs2_destroy_inode(struct inode *inode) | ||
453 | { | ||
454 | kmem_cache_free(gfs2_inode_cachep, inode); | ||
455 | } | ||
456 | |||
457 | struct super_operations gfs2_super_ops = { | ||
458 | .alloc_inode = gfs2_alloc_inode, | ||
459 | .destroy_inode = gfs2_destroy_inode, | ||
460 | .write_inode = gfs2_write_inode, | ||
461 | .delete_inode = gfs2_delete_inode, | ||
462 | .put_super = gfs2_put_super, | ||
463 | .write_super = gfs2_write_super, | ||
464 | .write_super_lockfs = gfs2_write_super_lockfs, | ||
465 | .unlockfs = gfs2_unlockfs, | ||
466 | .statfs = gfs2_statfs, | ||
467 | .remount_fs = gfs2_remount_fs, | ||
468 | .clear_inode = gfs2_clear_inode, | ||
469 | .show_options = gfs2_show_options, | ||
470 | }; | ||
471 | |||