blob: f1d599273d9e310874c0c75920a925a90c44d560 [file] [log] [blame]
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -07001/*
2 * the_nilfs.c - the_nilfs shared structure.
3 *
4 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * Written by Ryusuke Konishi <ryusuke@osrg.net>
21 *
22 */
23
24#include <linux/buffer_head.h>
25#include <linux/slab.h>
26#include <linux/blkdev.h>
27#include <linux/backing-dev.h>
Ryusuke Konishie339ad32009-04-06 19:01:59 -070028#include <linux/crc32.h>
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070029#include "nilfs.h"
30#include "segment.h"
31#include "alloc.h"
32#include "cpfile.h"
33#include "sufile.h"
34#include "dat.h"
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070035#include "segbuf.h"
36
Ryusuke Konishi33c8e572009-06-08 01:39:29 +090037
38static LIST_HEAD(nilfs_objects);
39static DEFINE_SPINLOCK(nilfs_lock);
40
Ryusuke Konishi6c1251602010-06-28 19:15:26 +090041static int nilfs_valid_sb(struct nilfs_super_block *sbp);
42
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070043void nilfs_set_last_segment(struct the_nilfs *nilfs,
44 sector_t start_blocknr, u64 seq, __u64 cno)
45{
46 spin_lock(&nilfs->ns_last_segment_lock);
47 nilfs->ns_last_pseg = start_blocknr;
48 nilfs->ns_last_seq = seq;
49 nilfs->ns_last_cno = cno;
Ryusuke Konishi32502042010-06-29 14:42:13 +090050
51 if (!nilfs_sb_dirty(nilfs)) {
52 if (nilfs->ns_prev_seq == nilfs->ns_last_seq)
53 goto stay_cursor;
54
55 set_nilfs_sb_dirty(nilfs);
56 }
57 nilfs->ns_prev_seq = nilfs->ns_last_seq;
58
59 stay_cursor:
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070060 spin_unlock(&nilfs->ns_last_segment_lock);
61}
62
63/**
64 * alloc_nilfs - allocate the_nilfs structure
65 * @bdev: block device to which the_nilfs is related
66 *
67 * alloc_nilfs() allocates memory for the_nilfs and
68 * initializes its reference count and locks.
69 *
70 * Return Value: On success, pointer to the_nilfs is returned.
71 * On error, NULL is returned.
72 */
Ryusuke Konishi33c8e572009-06-08 01:39:29 +090073static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070074{
75 struct the_nilfs *nilfs;
76
77 nilfs = kzalloc(sizeof(*nilfs), GFP_KERNEL);
78 if (!nilfs)
79 return NULL;
80
81 nilfs->ns_bdev = bdev;
82 atomic_set(&nilfs->ns_count, 1);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070083 atomic_set(&nilfs->ns_ndirtyblks, 0);
84 init_rwsem(&nilfs->ns_sem);
Ryusuke Konishie59399d2009-06-08 01:39:32 +090085 init_rwsem(&nilfs->ns_super_sem);
Ryusuke Konishiaa7dfb82009-06-08 01:39:33 +090086 mutex_init(&nilfs->ns_mount_mutex);
Ryusuke Konishi027d6402009-08-02 22:45:33 +090087 init_rwsem(&nilfs->ns_writer_sem);
Ryusuke Konishi33c8e572009-06-08 01:39:29 +090088 INIT_LIST_HEAD(&nilfs->ns_list);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070089 INIT_LIST_HEAD(&nilfs->ns_supers);
Ryusuke Konishi263d90c2010-08-20 19:06:11 +090090 INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070091 spin_lock_init(&nilfs->ns_last_segment_lock);
Ryusuke Konishiba65ae42010-08-14 12:59:15 +090092 nilfs->ns_cptree = RB_ROOT;
93 spin_lock_init(&nilfs->ns_cptree_lock);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070094 init_rwsem(&nilfs->ns_segctor_sem);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -070095
96 return nilfs;
97}
98
99/**
Ryusuke Konishi33c8e572009-06-08 01:39:29 +0900100 * find_or_create_nilfs - find or create nilfs object
101 * @bdev: block device to which the_nilfs is related
102 *
103 * find_nilfs() looks up an existent nilfs object created on the
104 * device and gets the reference count of the object. If no nilfs object
105 * is found on the device, a new nilfs object is allocated.
106 *
107 * Return Value: On success, pointer to the nilfs object is returned.
108 * On error, NULL is returned.
109 */
110struct the_nilfs *find_or_create_nilfs(struct block_device *bdev)
111{
112 struct the_nilfs *nilfs, *new = NULL;
113
114 retry:
115 spin_lock(&nilfs_lock);
116 list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
117 if (nilfs->ns_bdev == bdev) {
118 get_nilfs(nilfs);
119 spin_unlock(&nilfs_lock);
120 if (new)
121 put_nilfs(new);
122 return nilfs; /* existing object */
123 }
124 }
125 if (new) {
126 list_add_tail(&new->ns_list, &nilfs_objects);
127 spin_unlock(&nilfs_lock);
128 return new; /* new object */
129 }
130 spin_unlock(&nilfs_lock);
131
132 new = alloc_nilfs(bdev);
133 if (new)
134 goto retry;
135 return NULL; /* insufficient memory */
136}
137
138/**
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700139 * put_nilfs - release a reference to the_nilfs
140 * @nilfs: the_nilfs structure to be released
141 *
142 * put_nilfs() decrements a reference counter of the_nilfs.
143 * If the reference count reaches zero, the_nilfs is freed.
144 */
145void put_nilfs(struct the_nilfs *nilfs)
146{
Ryusuke Konishi33c8e572009-06-08 01:39:29 +0900147 spin_lock(&nilfs_lock);
148 if (!atomic_dec_and_test(&nilfs->ns_count)) {
149 spin_unlock(&nilfs_lock);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700150 return;
Ryusuke Konishi33c8e572009-06-08 01:39:29 +0900151 }
152 list_del_init(&nilfs->ns_list);
153 spin_unlock(&nilfs_lock);
154
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700155 /*
Ryusuke Konishi33c8e572009-06-08 01:39:29 +0900156 * Increment of ns_count never occurs below because the caller
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700157 * of get_nilfs() holds at least one reference to the_nilfs.
158 * Thus its exclusion control is not required here.
159 */
Ryusuke Konishi33c8e572009-06-08 01:39:29 +0900160
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700161 might_sleep();
162 if (nilfs_loaded(nilfs)) {
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700163 nilfs_mdt_destroy(nilfs->ns_sufile);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700164 nilfs_mdt_destroy(nilfs->ns_cpfile);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700165 nilfs_mdt_destroy(nilfs->ns_dat);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700166 nilfs_mdt_destroy(nilfs->ns_gc_dat);
167 }
168 if (nilfs_init(nilfs)) {
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700169 brelse(nilfs->ns_sbh[0]);
170 brelse(nilfs->ns_sbh[1]);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700171 }
172 kfree(nilfs);
173}
174
Ryusuke Konishi8b940252010-05-23 01:39:02 +0900175static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block)
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700176{
177 struct buffer_head *bh_sr;
178 struct nilfs_super_root *raw_sr;
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700179 struct nilfs_super_block **sbp = nilfs->ns_sbp;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700180 unsigned dat_entry_size, segment_usage_size, checkpoint_size;
181 unsigned inode_size;
182 int err;
183
Ryusuke Konishi8b940252010-05-23 01:39:02 +0900184 err = nilfs_read_super_root_block(nilfs, sr_block, &bh_sr, 1);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700185 if (unlikely(err))
186 return err;
187
188 down_read(&nilfs->ns_sem);
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700189 dat_entry_size = le16_to_cpu(sbp[0]->s_dat_entry_size);
190 checkpoint_size = le16_to_cpu(sbp[0]->s_checkpoint_size);
191 segment_usage_size = le16_to_cpu(sbp[0]->s_segment_usage_size);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700192 up_read(&nilfs->ns_sem);
193
194 inode_size = nilfs->ns_inode_size;
195
196 err = -ENOMEM;
Ryusuke Konishi79739562009-11-12 23:56:43 +0900197 nilfs->ns_dat = nilfs_dat_new(nilfs, dat_entry_size);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700198 if (unlikely(!nilfs->ns_dat))
199 goto failed;
200
Ryusuke Konishi79739562009-11-12 23:56:43 +0900201 nilfs->ns_gc_dat = nilfs_dat_new(nilfs, dat_entry_size);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700202 if (unlikely(!nilfs->ns_gc_dat))
203 goto failed_dat;
204
Ryusuke Konishi79739562009-11-12 23:56:43 +0900205 nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700206 if (unlikely(!nilfs->ns_cpfile))
207 goto failed_gc_dat;
208
Ryusuke Konishi79739562009-11-12 23:56:43 +0900209 nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700210 if (unlikely(!nilfs->ns_sufile))
211 goto failed_cpfile;
212
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700213 nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700214
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900215 err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data +
216 NILFS_SR_DAT_OFFSET(inode_size));
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700217 if (unlikely(err))
218 goto failed_sufile;
219
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900220 err = nilfs_cpfile_read(nilfs->ns_cpfile, (void *)bh_sr->b_data +
221 NILFS_SR_CPFILE_OFFSET(inode_size));
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700222 if (unlikely(err))
223 goto failed_sufile;
224
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900225 err = nilfs_sufile_read(nilfs->ns_sufile, (void *)bh_sr->b_data +
226 NILFS_SR_SUFILE_OFFSET(inode_size));
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700227 if (unlikely(err))
228 goto failed_sufile;
229
230 raw_sr = (struct nilfs_super_root *)bh_sr->b_data;
231 nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime);
232
233 failed:
234 brelse(bh_sr);
235 return err;
236
237 failed_sufile:
238 nilfs_mdt_destroy(nilfs->ns_sufile);
239
240 failed_cpfile:
241 nilfs_mdt_destroy(nilfs->ns_cpfile);
242
243 failed_gc_dat:
244 nilfs_mdt_destroy(nilfs->ns_gc_dat);
245
246 failed_dat:
247 nilfs_mdt_destroy(nilfs->ns_dat);
248 goto failed;
249}
250
251static void nilfs_init_recovery_info(struct nilfs_recovery_info *ri)
252{
253 memset(ri, 0, sizeof(*ri));
254 INIT_LIST_HEAD(&ri->ri_used_segments);
255}
256
257static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri)
258{
259 nilfs_dispose_segment_list(&ri->ri_used_segments);
260}
261
262/**
Ryusuke Konishi843d63b2010-06-28 19:15:24 +0900263 * nilfs_store_log_cursor - load log cursor from a super block
264 * @nilfs: nilfs object
265 * @sbp: buffer storing super block to be read
266 *
267 * nilfs_store_log_cursor() reads the last position of the log
268 * containing a super root from a given super block, and initializes
269 * relevant information on the nilfs object preparatory for log
270 * scanning and recovery.
271 */
272static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
273 struct nilfs_super_block *sbp)
274{
275 int ret = 0;
276
277 nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg);
278 nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
279 nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
280
Ryusuke Konishi32502042010-06-29 14:42:13 +0900281 nilfs->ns_prev_seq = nilfs->ns_last_seq;
Ryusuke Konishi843d63b2010-06-28 19:15:24 +0900282 nilfs->ns_seg_seq = nilfs->ns_last_seq;
283 nilfs->ns_segnum =
284 nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
285 nilfs->ns_cno = nilfs->ns_last_cno + 1;
286 if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
287 printk(KERN_ERR "NILFS invalid last segment number.\n");
288 ret = -EINVAL;
289 }
290 return ret;
291}
292
293/**
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700294 * load_nilfs - load and recover the nilfs
295 * @nilfs: the_nilfs structure to be released
296 * @sbi: nilfs_sb_info used to recover past segment
297 *
298 * load_nilfs() searches and load the latest super root,
299 * attaches the last segment, and does recovery if needed.
300 * The caller must call this exclusively for simultaneous mounts.
301 */
302int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
303{
304 struct nilfs_recovery_info ri;
305 unsigned int s_flags = sbi->s_super->s_flags;
306 int really_read_only = bdev_read_only(nilfs->ns_bdev);
Ryusuke Konishia057d2c2009-11-19 19:58:46 +0900307 int valid_fs = nilfs_valid_fs(nilfs);
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900308 int err;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700309
Ryusuke Konishi02345762009-11-20 03:28:01 +0900310 if (nilfs_loaded(nilfs)) {
311 if (valid_fs ||
312 ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY)))
313 return 0;
314 printk(KERN_ERR "NILFS: the filesystem is in an incomplete "
315 "recovery state.\n");
316 return -EINVAL;
317 }
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700318
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900319 if (!valid_fs) {
320 printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n");
321 if (s_flags & MS_RDONLY) {
322 printk(KERN_INFO "NILFS: INFO: recovery "
323 "required for readonly filesystem.\n");
324 printk(KERN_INFO "NILFS: write access will "
325 "be enabled during recovery.\n");
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700326 }
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700327 }
328
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900329 nilfs_init_recovery_info(&ri);
330
Ryusuke Konishi8b940252010-05-23 01:39:02 +0900331 err = nilfs_search_super_root(nilfs, &ri);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700332 if (unlikely(err)) {
Ryusuke Konishi6c1251602010-06-28 19:15:26 +0900333 struct nilfs_super_block **sbp = nilfs->ns_sbp;
334 int blocksize;
335
336 if (err != -EINVAL)
337 goto scan_error;
338
339 if (!nilfs_valid_sb(sbp[1])) {
340 printk(KERN_WARNING
341 "NILFS warning: unable to fall back to spare"
342 "super block\n");
343 goto scan_error;
344 }
345 printk(KERN_INFO
346 "NILFS: try rollback from an earlier position\n");
347
348 /*
349 * restore super block with its spare and reconfigure
350 * relevant states of the nilfs object.
351 */
352 memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
353 nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed);
354 nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
355
356 /* verify consistency between two super blocks */
357 blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
358 if (blocksize != nilfs->ns_blocksize) {
359 printk(KERN_WARNING
360 "NILFS warning: blocksize differs between "
361 "two super blocks (%d != %d)\n",
362 blocksize, nilfs->ns_blocksize);
363 goto scan_error;
364 }
365
366 err = nilfs_store_log_cursor(nilfs, sbp[0]);
367 if (err)
368 goto scan_error;
369
370 /* drop clean flag to allow roll-forward and recovery */
371 nilfs->ns_mount_state &= ~NILFS_VALID_FS;
372 valid_fs = 0;
373
374 err = nilfs_search_super_root(nilfs, &ri);
375 if (err)
376 goto scan_error;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700377 }
378
Ryusuke Konishi8b940252010-05-23 01:39:02 +0900379 err = nilfs_load_super_root(nilfs, ri.ri_super_root);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700380 if (unlikely(err)) {
381 printk(KERN_ERR "NILFS: error loading super root.\n");
382 goto failed;
383 }
384
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900385 if (valid_fs)
386 goto skip_recovery;
387
388 if (s_flags & MS_RDONLY) {
Ryusuke Konishic5ca48a2010-07-22 03:22:20 +0900389 __u64 features;
390
Ryusuke Konishi02345762009-11-20 03:28:01 +0900391 if (nilfs_test_opt(sbi, NORECOVERY)) {
392 printk(KERN_INFO "NILFS: norecovery option specified. "
393 "skipping roll-forward recovery\n");
394 goto skip_recovery;
395 }
Ryusuke Konishic5ca48a2010-07-22 03:22:20 +0900396 features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
397 ~NILFS_FEATURE_COMPAT_RO_SUPP;
398 if (features) {
399 printk(KERN_ERR "NILFS: couldn't proceed with "
400 "recovery because of unsupported optional "
401 "features (%llx)\n",
402 (unsigned long long)features);
403 err = -EROFS;
404 goto failed_unload;
405 }
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900406 if (really_read_only) {
407 printk(KERN_ERR "NILFS: write access "
408 "unavailable, cannot proceed.\n");
409 err = -EROFS;
410 goto failed_unload;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700411 }
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900412 sbi->s_super->s_flags &= ~MS_RDONLY;
Ryusuke Konishi02345762009-11-20 03:28:01 +0900413 } else if (nilfs_test_opt(sbi, NORECOVERY)) {
414 printk(KERN_ERR "NILFS: recovery cancelled because norecovery "
415 "option was specified for a read/write mount\n");
416 err = -EINVAL;
417 goto failed_unload;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700418 }
419
Ryusuke Konishiaee5ce22010-05-23 12:21:57 +0900420 err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900421 if (err)
422 goto failed_unload;
423
424 down_write(&nilfs->ns_sem);
Ryusuke Konishi7ecaa462010-06-28 17:49:29 +0900425 nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
426 err = nilfs_cleanup_super(sbi);
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900427 up_write(&nilfs->ns_sem);
428
429 if (err) {
430 printk(KERN_ERR "NILFS: failed to update super block. "
431 "recovery unfinished.\n");
432 goto failed_unload;
433 }
434 printk(KERN_INFO "NILFS: recovery complete.\n");
435
436 skip_recovery:
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700437 set_nilfs_loaded(nilfs);
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900438 nilfs_clear_recovery_info(&ri);
439 sbi->s_super->s_flags = s_flags;
440 return 0;
441
Ryusuke Konishi6c1251602010-06-28 19:15:26 +0900442 scan_error:
443 printk(KERN_ERR "NILFS: error searching super root.\n");
444 goto failed;
445
Ryusuke Konishif50a4c82009-11-19 16:58:40 +0900446 failed_unload:
447 nilfs_mdt_destroy(nilfs->ns_cpfile);
448 nilfs_mdt_destroy(nilfs->ns_sufile);
449 nilfs_mdt_destroy(nilfs->ns_dat);
Ryusuke Konishi4afc3132010-08-29 01:55:38 +0900450 nilfs_mdt_destroy(nilfs->ns_gc_dat);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700451
452 failed:
453 nilfs_clear_recovery_info(&ri);
454 sbi->s_super->s_flags = s_flags;
455 return err;
456}
457
458static unsigned long long nilfs_max_size(unsigned int blkbits)
459{
460 unsigned int max_bits;
461 unsigned long long res = MAX_LFS_FILESIZE; /* page cache limit */
462
463 max_bits = blkbits + NILFS_BMAP_KEY_BIT; /* bmap size limit */
464 if (max_bits < 64)
465 res = min_t(unsigned long long, res, (1ULL << max_bits) - 1);
466 return res;
467}
468
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700469static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
470 struct nilfs_super_block *sbp)
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700471{
Ryusuke Konishi9566a7a2010-08-10 00:58:41 +0900472 if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) {
473 printk(KERN_ERR "NILFS: unsupported revision "
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700474 "(superblock rev.=%d.%d, current rev.=%d.%d). "
475 "Please check the version of mkfs.nilfs.\n",
476 le32_to_cpu(sbp->s_rev_level),
477 le16_to_cpu(sbp->s_minor_rev_level),
478 NILFS_CURRENT_REV, NILFS_MINOR_REV);
479 return -EINVAL;
480 }
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700481 nilfs->ns_sbsize = le16_to_cpu(sbp->s_bytes);
482 if (nilfs->ns_sbsize > BLOCK_SIZE)
483 return -EINVAL;
484
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700485 nilfs->ns_inode_size = le16_to_cpu(sbp->s_inode_size);
486 nilfs->ns_first_ino = le32_to_cpu(sbp->s_first_ino);
487
488 nilfs->ns_blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment);
489 if (nilfs->ns_blocks_per_segment < NILFS_SEG_MIN_BLOCKS) {
Ryusuke Konishic91cea12010-03-14 04:01:27 +0900490 printk(KERN_ERR "NILFS: too short segment.\n");
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700491 return -EINVAL;
492 }
493
494 nilfs->ns_first_data_block = le64_to_cpu(sbp->s_first_data_block);
495 nilfs->ns_nsegments = le64_to_cpu(sbp->s_nsegments);
496 nilfs->ns_r_segments_percentage =
497 le32_to_cpu(sbp->s_r_segments_percentage);
498 nilfs->ns_nrsvsegs =
499 max_t(unsigned long, NILFS_MIN_NRSVSEGS,
500 DIV_ROUND_UP(nilfs->ns_nsegments *
501 nilfs->ns_r_segments_percentage, 100));
502 nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
503 return 0;
504}
505
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700506static int nilfs_valid_sb(struct nilfs_super_block *sbp)
507{
508 static unsigned char sum[4];
509 const int sumoff = offsetof(struct nilfs_super_block, s_sum);
510 size_t bytes;
511 u32 crc;
512
513 if (!sbp || le16_to_cpu(sbp->s_magic) != NILFS_SUPER_MAGIC)
514 return 0;
515 bytes = le16_to_cpu(sbp->s_bytes);
516 if (bytes > BLOCK_SIZE)
517 return 0;
518 crc = crc32_le(le32_to_cpu(sbp->s_crc_seed), (unsigned char *)sbp,
519 sumoff);
520 crc = crc32_le(crc, sum, 4);
521 crc = crc32_le(crc, (unsigned char *)sbp + sumoff + 4,
522 bytes - sumoff - 4);
523 return crc == le32_to_cpu(sbp->s_sum);
524}
525
526static int nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset)
527{
528 return offset < ((le64_to_cpu(sbp->s_nsegments) *
529 le32_to_cpu(sbp->s_blocks_per_segment)) <<
530 (le32_to_cpu(sbp->s_log_block_size) + 10));
531}
532
533static void nilfs_release_super_block(struct the_nilfs *nilfs)
534{
535 int i;
536
537 for (i = 0; i < 2; i++) {
538 if (nilfs->ns_sbp[i]) {
539 brelse(nilfs->ns_sbh[i]);
540 nilfs->ns_sbh[i] = NULL;
541 nilfs->ns_sbp[i] = NULL;
542 }
543 }
544}
545
546void nilfs_fall_back_super_block(struct the_nilfs *nilfs)
547{
548 brelse(nilfs->ns_sbh[0]);
549 nilfs->ns_sbh[0] = nilfs->ns_sbh[1];
550 nilfs->ns_sbp[0] = nilfs->ns_sbp[1];
551 nilfs->ns_sbh[1] = NULL;
552 nilfs->ns_sbp[1] = NULL;
553}
554
555void nilfs_swap_super_block(struct the_nilfs *nilfs)
556{
557 struct buffer_head *tsbh = nilfs->ns_sbh[0];
558 struct nilfs_super_block *tsbp = nilfs->ns_sbp[0];
559
560 nilfs->ns_sbh[0] = nilfs->ns_sbh[1];
561 nilfs->ns_sbp[0] = nilfs->ns_sbp[1];
562 nilfs->ns_sbh[1] = tsbh;
563 nilfs->ns_sbp[1] = tsbp;
564}
565
566static int nilfs_load_super_block(struct the_nilfs *nilfs,
567 struct super_block *sb, int blocksize,
568 struct nilfs_super_block **sbpp)
569{
570 struct nilfs_super_block **sbp = nilfs->ns_sbp;
571 struct buffer_head **sbh = nilfs->ns_sbh;
572 u64 sb2off = NILFS_SB2_OFFSET_BYTES(nilfs->ns_bdev->bd_inode->i_size);
573 int valid[2], swp = 0;
574
575 sbp[0] = nilfs_read_super_block(sb, NILFS_SB_OFFSET_BYTES, blocksize,
576 &sbh[0]);
577 sbp[1] = nilfs_read_super_block(sb, sb2off, blocksize, &sbh[1]);
578
579 if (!sbp[0]) {
580 if (!sbp[1]) {
581 printk(KERN_ERR "NILFS: unable to read superblock\n");
582 return -EIO;
583 }
584 printk(KERN_WARNING
585 "NILFS warning: unable to read primary superblock\n");
586 } else if (!sbp[1])
587 printk(KERN_WARNING
588 "NILFS warning: unable to read secondary superblock\n");
589
Ryusuke Konishi25294d82010-05-01 11:54:21 +0900590 /*
591 * Compare two super blocks and set 1 in swp if the secondary
592 * super block is valid and newer. Otherwise, set 0 in swp.
593 */
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700594 valid[0] = nilfs_valid_sb(sbp[0]);
595 valid[1] = nilfs_valid_sb(sbp[1]);
Ryusuke Konishi25294d82010-05-01 11:54:21 +0900596 swp = valid[1] && (!valid[0] ||
597 le64_to_cpu(sbp[1]->s_last_cno) >
598 le64_to_cpu(sbp[0]->s_last_cno));
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700599
600 if (valid[swp] && nilfs_sb2_bad_offset(sbp[swp], sb2off)) {
601 brelse(sbh[1]);
602 sbh[1] = NULL;
603 sbp[1] = NULL;
604 swp = 0;
605 }
606 if (!valid[swp]) {
607 nilfs_release_super_block(nilfs);
608 printk(KERN_ERR "NILFS: Can't find nilfs on dev %s.\n",
609 sb->s_id);
610 return -EINVAL;
611 }
612
Ryusuke Konishiea1a16f2010-08-15 20:16:11 +0900613 if (!valid[!swp])
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700614 printk(KERN_WARNING "NILFS warning: broken superblock. "
615 "using spare superblock.\n");
Ryusuke Konishiea1a16f2010-08-15 20:16:11 +0900616 if (swp)
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700617 nilfs_swap_super_block(nilfs);
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700618
Jiro SEKIBAb2ac86e2010-06-28 17:49:33 +0900619 nilfs->ns_sbwcount = 0;
620 nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700621 nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq);
622 *sbpp = sbp[0];
623 return 0;
624}
625
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700626/**
627 * init_nilfs - initialize a NILFS instance.
628 * @nilfs: the_nilfs structure
629 * @sbi: nilfs_sb_info
630 * @sb: super block
631 * @data: mount options
632 *
633 * init_nilfs() performs common initialization per block device (e.g.
634 * reading the super block, getting disk layout information, initializing
635 * shared fields in the_nilfs). It takes on some portion of the jobs
636 * typically done by a fill_super() routine. This division arises from
637 * the nature that multiple NILFS instances may be simultaneously
638 * mounted on a device.
639 * For multiple mounts on the same device, only the first mount
640 * invokes these tasks.
641 *
642 * Return Value: On success, 0 is returned. On error, a negative error
643 * code is returned.
644 */
645int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
646{
647 struct super_block *sb = sbi->s_super;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700648 struct nilfs_super_block *sbp;
649 struct backing_dev_info *bdi;
650 int blocksize;
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700651 int err;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700652
653 down_write(&nilfs->ns_sem);
654 if (nilfs_init(nilfs)) {
655 /* Load values from existing the_nilfs */
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700656 sbp = nilfs->ns_sbp[0];
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700657 err = nilfs_store_magic_and_option(sb, sbp, data);
658 if (err)
659 goto out;
660
Ryusuke Konishic5ca48a2010-07-22 03:22:20 +0900661 err = nilfs_check_feature_compatibility(sb, sbp);
662 if (err)
663 goto out;
664
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700665 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
666 if (sb->s_blocksize != blocksize &&
667 !sb_set_blocksize(sb, blocksize)) {
668 printk(KERN_ERR "NILFS: blocksize %d unfit to device\n",
669 blocksize);
670 err = -EINVAL;
671 }
672 sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits);
673 goto out;
674 }
675
Ryusuke Konishi89c0fd02010-07-25 22:44:53 +0900676 blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE);
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700677 if (!blocksize) {
678 printk(KERN_ERR "NILFS: unable to set blocksize\n");
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700679 err = -EINVAL;
680 goto out;
681 }
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700682 err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp);
683 if (err)
684 goto out;
685
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700686 err = nilfs_store_magic_and_option(sb, sbp, data);
687 if (err)
688 goto failed_sbh;
689
Ryusuke Konishic5ca48a2010-07-22 03:22:20 +0900690 err = nilfs_check_feature_compatibility(sb, sbp);
691 if (err)
692 goto failed_sbh;
693
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700694 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
Ryusuke Konishi89c0fd02010-07-25 22:44:53 +0900695 if (blocksize < NILFS_MIN_BLOCK_SIZE ||
696 blocksize > NILFS_MAX_BLOCK_SIZE) {
697 printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
698 "filesystem blocksize %d\n", blocksize);
699 err = -EINVAL;
700 goto failed_sbh;
701 }
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700702 if (sb->s_blocksize != blocksize) {
Martin K. Petersene1defc42009-05-22 17:17:49 -0400703 int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700704
705 if (blocksize < hw_blocksize) {
706 printk(KERN_ERR
707 "NILFS: blocksize %d too small for device "
708 "(sector-size = %d).\n",
709 blocksize, hw_blocksize);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700710 err = -EINVAL;
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700711 goto failed_sbh;
712 }
713 nilfs_release_super_block(nilfs);
714 sb_set_blocksize(sb, blocksize);
715
716 err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp);
717 if (err)
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700718 goto out;
719 /* not failed_sbh; sbh is released automatically
720 when reloading fails. */
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700721 }
722 nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
Ryusuke Konishi92c60cc2010-05-23 00:17:48 +0900723 nilfs->ns_blocksize = blocksize;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700724
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700725 err = nilfs_store_disk_layout(nilfs, sbp);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700726 if (err)
727 goto failed_sbh;
728
729 sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits);
730
731 nilfs->ns_mount_state = le16_to_cpu(sbp->s_state);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700732
Jens Axboe2c96ce92009-09-15 09:43:56 +0200733 bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700734 nilfs->ns_bdi = bdi ? : &default_backing_dev_info;
735
Ryusuke Konishi843d63b2010-06-28 19:15:24 +0900736 err = nilfs_store_log_cursor(nilfs, sbp);
737 if (err)
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700738 goto failed_sbh;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700739
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700740 set_nilfs_init(nilfs);
741 err = 0;
742 out:
743 up_write(&nilfs->ns_sem);
744 return err;
745
746 failed_sbh:
Ryusuke Konishie339ad32009-04-06 19:01:59 -0700747 nilfs_release_super_block(nilfs);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700748 goto out;
749}
750
Jiro SEKIBAe902ec92010-01-30 18:06:35 +0900751int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
752 size_t nsegs)
753{
754 sector_t seg_start, seg_end;
755 sector_t start = 0, nblocks = 0;
756 unsigned int sects_per_block;
757 __u64 *sn;
758 int ret = 0;
759
760 sects_per_block = (1 << nilfs->ns_blocksize_bits) /
761 bdev_logical_block_size(nilfs->ns_bdev);
762 for (sn = segnump; sn < segnump + nsegs; sn++) {
763 nilfs_get_segment_range(nilfs, *sn, &seg_start, &seg_end);
764
765 if (!nblocks) {
766 start = seg_start;
767 nblocks = seg_end - seg_start + 1;
768 } else if (start + nblocks == seg_start) {
769 nblocks += seg_end - seg_start + 1;
770 } else {
771 ret = blkdev_issue_discard(nilfs->ns_bdev,
772 start * sects_per_block,
773 nblocks * sects_per_block,
774 GFP_NOFS,
Ryusuke Konishi1cb0c922010-08-18 21:11:11 +0900775 BLKDEV_IFL_WAIT |
Stephen Rothwell6a47dc12010-04-29 09:32:00 +0200776 BLKDEV_IFL_BARRIER);
Jiro SEKIBAe902ec92010-01-30 18:06:35 +0900777 if (ret < 0)
778 return ret;
779 nblocks = 0;
780 }
781 }
782 if (nblocks)
783 ret = blkdev_issue_discard(nilfs->ns_bdev,
784 start * sects_per_block,
785 nblocks * sects_per_block,
Ryusuke Konishi1cb0c922010-08-18 21:11:11 +0900786 GFP_NOFS,
787 BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER);
Jiro SEKIBAe902ec92010-01-30 18:06:35 +0900788 return ret;
789}
790
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700791int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
792{
793 struct inode *dat = nilfs_dat_inode(nilfs);
794 unsigned long ncleansegs;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700795
796 down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */
Ryusuke Konishief7d4752009-11-13 08:45:32 +0900797 ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700798 up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */
Ryusuke Konishief7d4752009-11-13 08:45:32 +0900799 *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment;
800 return 0;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700801}
802
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700803int nilfs_near_disk_full(struct the_nilfs *nilfs)
804{
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700805 unsigned long ncleansegs, nincsegs;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700806
Ryusuke Konishief7d4752009-11-13 08:45:32 +0900807 ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile);
808 nincsegs = atomic_read(&nilfs->ns_ndirtyblks) /
809 nilfs->ns_blocks_per_segment + 1;
810
811 return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs;
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700812}
813
Ryusuke Konishiba65ae42010-08-14 12:59:15 +0900814struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno)
815{
816 struct rb_node *n;
817 struct nilfs_root *root;
818
819 spin_lock(&nilfs->ns_cptree_lock);
820 n = nilfs->ns_cptree.rb_node;
821 while (n) {
822 root = rb_entry(n, struct nilfs_root, rb_node);
823
824 if (cno < root->cno) {
825 n = n->rb_left;
826 } else if (cno > root->cno) {
827 n = n->rb_right;
828 } else {
829 atomic_inc(&root->count);
830 spin_unlock(&nilfs->ns_cptree_lock);
831 return root;
832 }
833 }
834 spin_unlock(&nilfs->ns_cptree_lock);
835
836 return NULL;
837}
838
839struct nilfs_root *
840nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno)
841{
842 struct rb_node **p, *parent;
843 struct nilfs_root *root, *new;
844
845 root = nilfs_lookup_root(nilfs, cno);
846 if (root)
847 return root;
848
849 new = kmalloc(sizeof(*root), GFP_KERNEL);
850 if (!new)
851 return NULL;
852
853 spin_lock(&nilfs->ns_cptree_lock);
854
855 p = &nilfs->ns_cptree.rb_node;
856 parent = NULL;
857
858 while (*p) {
859 parent = *p;
860 root = rb_entry(parent, struct nilfs_root, rb_node);
861
862 if (cno < root->cno) {
863 p = &(*p)->rb_left;
864 } else if (cno > root->cno) {
865 p = &(*p)->rb_right;
866 } else {
867 atomic_inc(&root->count);
868 spin_unlock(&nilfs->ns_cptree_lock);
869 kfree(new);
870 return root;
871 }
872 }
873
874 new->cno = cno;
875 new->ifile = NULL;
876 new->nilfs = nilfs;
877 atomic_set(&new->count, 1);
878 atomic_set(&new->inodes_count, 0);
879 atomic_set(&new->blocks_count, 0);
880
881 rb_link_node(&new->rb_node, parent, p);
882 rb_insert_color(&new->rb_node, &nilfs->ns_cptree);
883
884 spin_unlock(&nilfs->ns_cptree_lock);
885
886 return new;
887}
888
889void nilfs_put_root(struct nilfs_root *root)
890{
891 if (atomic_dec_and_test(&root->count)) {
892 struct the_nilfs *nilfs = root->nilfs;
893
894 spin_lock(&nilfs->ns_cptree_lock);
895 rb_erase(&root->rb_node, &nilfs->ns_cptree);
896 spin_unlock(&nilfs->ns_cptree_lock);
897 if (root->ifile)
898 nilfs_mdt_destroy(root->ifile);
899
900 kfree(root);
901 }
902}
903
Ryusuke Konishi6dd47402009-06-08 01:39:31 +0900904/**
905 * nilfs_find_sbinfo - find existing nilfs_sb_info structure
906 * @nilfs: nilfs object
907 * @rw_mount: mount type (non-zero value for read/write mount)
908 * @cno: checkpoint number (zero for read-only mount)
909 *
910 * nilfs_find_sbinfo() returns the nilfs_sb_info structure which
911 * @rw_mount and @cno (in case of snapshots) matched. If no instance
912 * was found, NULL is returned. Although the super block instance can
913 * be unmounted after this function returns, the nilfs_sb_info struct
914 * is kept on memory until nilfs_put_sbinfo() is called.
915 */
916struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs,
917 int rw_mount, __u64 cno)
918{
919 struct nilfs_sb_info *sbi;
920
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900921 down_read(&nilfs->ns_super_sem);
Ryusuke Konishi6dd47402009-06-08 01:39:31 +0900922 /*
923 * The SNAPSHOT flag and sb->s_flags are supposed to be
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900924 * protected with nilfs->ns_super_sem.
Ryusuke Konishi6dd47402009-06-08 01:39:31 +0900925 */
926 sbi = nilfs->ns_current;
927 if (rw_mount) {
928 if (sbi && !(sbi->s_super->s_flags & MS_RDONLY))
929 goto found; /* read/write mount */
930 else
931 goto out;
932 } else if (cno == 0) {
933 if (sbi && (sbi->s_super->s_flags & MS_RDONLY))
934 goto found; /* read-only mount */
935 else
936 goto out;
937 }
938
939 list_for_each_entry(sbi, &nilfs->ns_supers, s_list) {
940 if (nilfs_test_opt(sbi, SNAPSHOT) &&
941 sbi->s_snapshot_cno == cno)
942 goto found; /* snapshot mount */
943 }
944 out:
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900945 up_read(&nilfs->ns_super_sem);
Ryusuke Konishi6dd47402009-06-08 01:39:31 +0900946 return NULL;
947
948 found:
949 atomic_inc(&sbi->s_count);
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900950 up_read(&nilfs->ns_super_sem);
Ryusuke Konishi6dd47402009-06-08 01:39:31 +0900951 return sbi;
952}
953
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700954int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
955 int snapshot_mount)
956{
957 struct nilfs_sb_info *sbi;
958 int ret = 0;
959
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900960 down_read(&nilfs->ns_super_sem);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700961 if (cno == 0 || cno > nilfs->ns_cno)
962 goto out_unlock;
963
964 list_for_each_entry(sbi, &nilfs->ns_supers, s_list) {
965 if (sbi->s_snapshot_cno == cno &&
966 (!snapshot_mount || nilfs_test_opt(sbi, SNAPSHOT))) {
967 /* exclude read-only mounts */
968 ret++;
969 break;
970 }
971 }
972 /* for protecting recent checkpoints */
973 if (cno >= nilfs_last_cno(nilfs))
974 ret++;
975
976 out_unlock:
Ryusuke Konishie59399d2009-06-08 01:39:32 +0900977 up_read(&nilfs->ns_super_sem);
Ryusuke Konishi8a9d2192009-04-06 19:01:35 -0700978 return ret;
979}