segbuf.c 13.7 KB
Newer Older
Ryusuke Konishi's avatar
Ryusuke Konishi committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * segbuf.c - NILFS segment buffer
 *
 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Written by Ryusuke Konishi <ryusuke@osrg.net>
 *
 */

#include <linux/buffer_head.h>
#include <linux/writeback.h>
#include <linux/crc32.h>
27
#include <linux/backing-dev.h>
28
#include <linux/slab.h>
Ryusuke Konishi's avatar
Ryusuke Konishi committed
29
30
31
32
#include "page.h"
#include "segbuf.h"


33
34
35
struct nilfs_write_info {
	struct the_nilfs       *nilfs;
	struct bio	       *bio;
36
	int			start, end; /* The region to be submitted */
37
38
39
40
41
42
	int			rest_blocks;
	int			max_pages;
	int			nr_vecs;
	sector_t		blocknr;
};

43
44
45
46
static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
			      struct the_nilfs *nilfs);
static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf);

Ryusuke Konishi's avatar
Ryusuke Konishi committed
47
48
49
50
51
52
53
54
55
56
57
58
struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *sb)
{
	struct nilfs_segment_buffer *segbuf;

	segbuf = kmem_cache_alloc(nilfs_segbuf_cachep, GFP_NOFS);
	if (unlikely(!segbuf))
		return NULL;

	segbuf->sb_super = sb;
	INIT_LIST_HEAD(&segbuf->sb_list);
	INIT_LIST_HEAD(&segbuf->sb_segsum_buffers);
	INIT_LIST_HEAD(&segbuf->sb_payload_buffers);
59
	segbuf->sb_super_root = NULL;
60
61
62
63
64

	init_completion(&segbuf->sb_bio_event);
	atomic_set(&segbuf->sb_err, 0);
	segbuf->sb_nbio = 0;

Ryusuke Konishi's avatar
Ryusuke Konishi committed
65
66
67
68
69
70
71
72
	return segbuf;
}

void nilfs_segbuf_free(struct nilfs_segment_buffer *segbuf)
{
	kmem_cache_free(nilfs_segbuf_cachep, segbuf);
}

73
void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum,
Ryusuke Konishi's avatar
Ryusuke Konishi committed
74
75
76
77
78
79
80
81
82
83
84
		     unsigned long offset, struct the_nilfs *nilfs)
{
	segbuf->sb_segnum = segnum;
	nilfs_get_segment_range(nilfs, segnum, &segbuf->sb_fseg_start,
				&segbuf->sb_fseg_end);

	segbuf->sb_pseg_start = segbuf->sb_fseg_start + offset;
	segbuf->sb_rest_blocks =
		segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;
}

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
 * nilfs_segbuf_map_cont - map a new log behind a given log
 * @segbuf: new segment buffer
 * @prev: segment buffer containing a log to be continued
 */
void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf,
			   struct nilfs_segment_buffer *prev)
{
	segbuf->sb_segnum = prev->sb_segnum;
	segbuf->sb_fseg_start = prev->sb_fseg_start;
	segbuf->sb_fseg_end = prev->sb_fseg_end;
	segbuf->sb_pseg_start = prev->sb_pseg_start + prev->sb_sum.nblocks;
	segbuf->sb_rest_blocks =
		segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;
}

Ryusuke Konishi's avatar
Ryusuke Konishi committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *segbuf,
				  __u64 nextnum, struct the_nilfs *nilfs)
{
	segbuf->sb_nextnum = nextnum;
	segbuf->sb_sum.next = nilfs_get_segment_start_blocknr(nilfs, nextnum);
}

int nilfs_segbuf_extend_segsum(struct nilfs_segment_buffer *segbuf)
{
	struct buffer_head *bh;

	bh = sb_getblk(segbuf->sb_super,
		       segbuf->sb_pseg_start + segbuf->sb_sum.nsumblk);
	if (unlikely(!bh))
		return -ENOMEM;

	nilfs_segbuf_add_segsum_buffer(segbuf, bh);
	return 0;
}

int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *segbuf,
				struct buffer_head **bhp)
{
	struct buffer_head *bh;

	bh = sb_getblk(segbuf->sb_super,
		       segbuf->sb_pseg_start + segbuf->sb_sum.nblocks);
	if (unlikely(!bh))
		return -ENOMEM;

	nilfs_segbuf_add_payload_buffer(segbuf, bh);
	*bhp = bh;
	return 0;
}

int nilfs_segbuf_reset(struct nilfs_segment_buffer *segbuf, unsigned flags,
137
		       time_t ctime, __u64 cno)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
138
139
140
141
142
143
144
145
146
147
148
149
{
	int err;

	segbuf->sb_sum.nblocks = segbuf->sb_sum.nsumblk = 0;
	err = nilfs_segbuf_extend_segsum(segbuf);
	if (unlikely(err))
		return err;

	segbuf->sb_sum.flags = flags;
	segbuf->sb_sum.sumbytes = sizeof(struct nilfs_segment_summary);
	segbuf->sb_sum.nfinfo = segbuf->sb_sum.nfileblk = 0;
	segbuf->sb_sum.ctime = ctime;
150
	segbuf->sb_sum.cno = cno;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
151
152
153
154
	return 0;
}

/*
155
 * Setup segment summary
Ryusuke Konishi's avatar
Ryusuke Konishi committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
 */
void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *segbuf)
{
	struct nilfs_segment_summary *raw_sum;
	struct buffer_head *bh_sum;

	bh_sum = list_entry(segbuf->sb_segsum_buffers.next,
			    struct buffer_head, b_assoc_buffers);
	raw_sum = (struct nilfs_segment_summary *)bh_sum->b_data;

	raw_sum->ss_magic    = cpu_to_le32(NILFS_SEGSUM_MAGIC);
	raw_sum->ss_bytes    = cpu_to_le16(sizeof(*raw_sum));
	raw_sum->ss_flags    = cpu_to_le16(segbuf->sb_sum.flags);
	raw_sum->ss_seq      = cpu_to_le64(segbuf->sb_sum.seg_seq);
	raw_sum->ss_create   = cpu_to_le64(segbuf->sb_sum.ctime);
	raw_sum->ss_next     = cpu_to_le64(segbuf->sb_sum.next);
	raw_sum->ss_nblocks  = cpu_to_le32(segbuf->sb_sum.nblocks);
	raw_sum->ss_nfinfo   = cpu_to_le32(segbuf->sb_sum.nfinfo);
	raw_sum->ss_sumbytes = cpu_to_le32(segbuf->sb_sum.sumbytes);
	raw_sum->ss_pad      = 0;
176
	raw_sum->ss_cno      = cpu_to_le64(segbuf->sb_sum.cno);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
177
178
179
180
181
}

/*
 * CRC calculation routines
 */
182
183
static void
nilfs_segbuf_fill_in_segsum_crc(struct nilfs_segment_buffer *segbuf, u32 seed)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
{
	struct buffer_head *bh;
	struct nilfs_segment_summary *raw_sum;
	unsigned long size, bytes = segbuf->sb_sum.sumbytes;
	u32 crc;

	bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,
			b_assoc_buffers);

	raw_sum = (struct nilfs_segment_summary *)bh->b_data;
	size = min_t(unsigned long, bytes, bh->b_size);
	crc = crc32_le(seed,
		       (unsigned char *)raw_sum +
		       sizeof(raw_sum->ss_datasum) + sizeof(raw_sum->ss_sumsum),
		       size - (sizeof(raw_sum->ss_datasum) +
			       sizeof(raw_sum->ss_sumsum)));

	list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,
				     b_assoc_buffers) {
		bytes -= size;
		size = min_t(unsigned long, bytes, bh->b_size);
		crc = crc32_le(crc, bh->b_data, size);
	}
	raw_sum->ss_sumsum = cpu_to_le32(crc);
}

210
211
static void nilfs_segbuf_fill_in_data_crc(struct nilfs_segment_buffer *segbuf,
					  u32 seed)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
{
	struct buffer_head *bh;
	struct nilfs_segment_summary *raw_sum;
	void *kaddr;
	u32 crc;

	bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,
			b_assoc_buffers);
	raw_sum = (struct nilfs_segment_summary *)bh->b_data;
	crc = crc32_le(seed,
		       (unsigned char *)raw_sum + sizeof(raw_sum->ss_datasum),
		       bh->b_size - sizeof(raw_sum->ss_datasum));

	list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,
				     b_assoc_buffers) {
		crc = crc32_le(crc, bh->b_data, bh->b_size);
	}
	list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {
230
		kaddr = kmap_atomic(bh->b_page);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
231
		crc = crc32_le(crc, kaddr + bh_offset(bh), bh->b_size);
232
		kunmap_atomic(kaddr);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
233
234
235
236
	}
	raw_sum->ss_datasum = cpu_to_le32(crc);
}

237
238
239
240
241
static void
nilfs_segbuf_fill_in_super_root_crc(struct nilfs_segment_buffer *segbuf,
				    u32 seed)
{
	struct nilfs_super_root *raw_sr;
242
243
	struct the_nilfs *nilfs = segbuf->sb_super->s_fs_info;
	unsigned srsize;
244
245
246
	u32 crc;

	raw_sr = (struct nilfs_super_root *)segbuf->sb_super_root->b_data;
247
	srsize = NILFS_SR_BYTES(nilfs->ns_inode_size);
248
249
	crc = crc32_le(seed,
		       (unsigned char *)raw_sr + sizeof(raw_sr->sr_sum),
250
		       srsize - sizeof(raw_sr->sr_sum));
251
252
253
	raw_sr->sr_sum = cpu_to_le32(crc);
}

254
static void nilfs_release_buffers(struct list_head *list)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
255
256
257
258
259
260
261
262
263
{
	struct buffer_head *bh, *n;

	list_for_each_entry_safe(bh, n, list, b_assoc_buffers) {
		list_del_init(&bh->b_assoc_buffers);
		brelse(bh);
	}
}

264
265
266
267
static void nilfs_segbuf_clear(struct nilfs_segment_buffer *segbuf)
{
	nilfs_release_buffers(&segbuf->sb_segsum_buffers);
	nilfs_release_buffers(&segbuf->sb_payload_buffers);
268
	segbuf->sb_super_root = NULL;
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
}

/*
 * Iterators for segment buffers
 */
void nilfs_clear_logs(struct list_head *logs)
{
	struct nilfs_segment_buffer *segbuf;

	list_for_each_entry(segbuf, logs, sb_list)
		nilfs_segbuf_clear(segbuf);
}

void nilfs_truncate_logs(struct list_head *logs,
			 struct nilfs_segment_buffer *last)
{
	struct nilfs_segment_buffer *n, *segbuf;

	segbuf = list_prepare_entry(last, logs, sb_list);
	list_for_each_entry_safe_continue(segbuf, n, logs, sb_list) {
		list_del_init(&segbuf->sb_list);
		nilfs_segbuf_clear(segbuf);
		nilfs_segbuf_free(segbuf);
	}
}

295
296
297
298
299
300
301
302
303
304
305
306
307
int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs)
{
	struct nilfs_segment_buffer *segbuf;
	int ret = 0;

	list_for_each_entry(segbuf, logs, sb_list) {
		ret = nilfs_segbuf_write(segbuf, nilfs);
		if (ret)
			break;
	}
	return ret;
}

308
309
310
int nilfs_wait_on_logs(struct list_head *logs)
{
	struct nilfs_segment_buffer *segbuf;
311
	int err, ret = 0;
312
313
314

	list_for_each_entry(segbuf, logs, sb_list) {
		err = nilfs_segbuf_wait(segbuf);
315
316
		if (err && !ret)
			ret = err;
317
	}
318
	return ret;
319
320
}

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/**
 * nilfs_add_checksums_on_logs - add checksums on the logs
 * @logs: list of segment buffers storing target logs
 * @seed: checksum seed value
 */
void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed)
{
	struct nilfs_segment_buffer *segbuf;

	list_for_each_entry(segbuf, logs, sb_list) {
		if (segbuf->sb_super_root)
			nilfs_segbuf_fill_in_super_root_crc(segbuf, seed);
		nilfs_segbuf_fill_in_segsum_crc(segbuf, seed);
		nilfs_segbuf_fill_in_data_crc(segbuf, seed);
	}
}

Ryusuke Konishi's avatar
Ryusuke Konishi committed
338
339
340
341
342
343
/*
 * BIO operations
 */
static void nilfs_end_bio_write(struct bio *bio, int err)
{
	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
344
	struct nilfs_segment_buffer *segbuf = bio->bi_private;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
345
346
347

	if (err == -EOPNOTSUPP) {
		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
348
		/* to be detected by nilfs_segbuf_submit_bio() */
Ryusuke Konishi's avatar
Ryusuke Konishi committed
349
350
351
	}

	if (!uptodate)
352
		atomic_inc(&segbuf->sb_err);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
353
354

	bio_put(bio);
355
	complete(&segbuf->sb_bio_event);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
356
357
}

358
359
static int nilfs_segbuf_submit_bio(struct nilfs_segment_buffer *segbuf,
				   struct nilfs_write_info *wi, int mode)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
360
361
362
363
{
	struct bio *bio = wi->bio;
	int err;

364
365
	if (segbuf->sb_nbio > 0 &&
	    bdi_write_congested(segbuf->sb_super->s_bdi)) {
366
367
368
		wait_for_completion(&segbuf->sb_bio_event);
		segbuf->sb_nbio--;
		if (unlikely(atomic_read(&segbuf->sb_err))) {
Ryusuke Konishi's avatar
Ryusuke Konishi committed
369
370
371
372
373
374
375
			bio_put(bio);
			err = -EIO;
			goto failed;
		}
	}

	bio->bi_end_io = nilfs_end_bio_write;
376
	bio->bi_private = segbuf;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
377
378
	bio_get(bio);
	submit_bio(mode, bio);
379
	segbuf->sb_nbio++;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
	if (bio_flagged(bio, BIO_EOPNOTSUPP)) {
		bio_put(bio);
		err = -EOPNOTSUPP;
		goto failed;
	}
	bio_put(bio);

	wi->bio = NULL;
	wi->rest_blocks -= wi->end - wi->start;
	wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);
	wi->start = wi->end;
	return 0;

 failed:
	wi->bio = NULL;
	return err;
}

/**
399
400
401
 * nilfs_alloc_seg_bio - allocate a new bio for writing log
 * @nilfs: nilfs object
 * @start: start block number of the bio
Ryusuke Konishi's avatar
Ryusuke Konishi committed
402
403
404
405
406
 * @nr_vecs: request size of page vector.
 *
 * Return Value: On success, pointer to the struct bio is returned.
 * On error, NULL is returned.
 */
407
static struct bio *nilfs_alloc_seg_bio(struct the_nilfs *nilfs, sector_t start,
Ryusuke Konishi's avatar
Ryusuke Konishi committed
408
409
410
411
				       int nr_vecs)
{
	struct bio *bio;

412
	bio = bio_alloc(GFP_NOIO, nr_vecs);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
413
414
	if (bio == NULL) {
		while (!bio && (nr_vecs >>= 1))
415
			bio = bio_alloc(GFP_NOIO, nr_vecs);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
416
417
	}
	if (likely(bio)) {
418
419
		bio->bi_bdev = nilfs->ns_bdev;
		bio->bi_sector = start << (nilfs->ns_blocksize_bits - 9);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
420
421
422
423
	}
	return bio;
}

424
425
static void nilfs_segbuf_prepare_write(struct nilfs_segment_buffer *segbuf,
				       struct nilfs_write_info *wi)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
426
427
428
{
	wi->bio = NULL;
	wi->rest_blocks = segbuf->sb_sum.nblocks;
429
	wi->max_pages = bio_get_nr_vecs(wi->nilfs->ns_bdev);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
430
431
432
433
434
	wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);
	wi->start = wi->end = 0;
	wi->blocknr = segbuf->sb_pseg_start;
}

435
436
437
static int nilfs_segbuf_submit_bh(struct nilfs_segment_buffer *segbuf,
				  struct nilfs_write_info *wi,
				  struct buffer_head *bh, int mode)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
438
439
440
441
442
443
{
	int len, err;

	BUG_ON(wi->nr_vecs <= 0);
 repeat:
	if (!wi->bio) {
444
		wi->bio = nilfs_alloc_seg_bio(wi->nilfs, wi->blocknr + wi->end,
Ryusuke Konishi's avatar
Ryusuke Konishi committed
445
446
447
448
449
450
451
452
453
454
455
					      wi->nr_vecs);
		if (unlikely(!wi->bio))
			return -ENOMEM;
	}

	len = bio_add_page(wi->bio, bh->b_page, bh->b_size, bh_offset(bh));
	if (len == bh->b_size) {
		wi->end++;
		return 0;
	}
	/* bio is FULL */
456
	err = nilfs_segbuf_submit_bio(segbuf, wi, mode);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
457
458
459
460
461
462
	/* never submit current bh */
	if (likely(!err))
		goto repeat;
	return err;
}

463
464
465
466
467
468
469
470
471
472
473
474
/**
 * nilfs_segbuf_write - submit write requests of a log
 * @segbuf: buffer storing a log to be written
 * @nilfs: nilfs object
 *
 * Return Value: On Success, 0 is returned. On Error, one of the following
 * negative error code is returned.
 *
 * %-EIO - I/O error
 *
 * %-ENOMEM - Insufficient memory available.
 */
475
476
static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
			      struct the_nilfs *nilfs)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
477
{
478
	struct nilfs_write_info wi;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
479
	struct buffer_head *bh;
480
	int res = 0, rw = WRITE;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
481

482
483
484
	wi.nilfs = nilfs;
	nilfs_segbuf_prepare_write(segbuf, &wi);

Ryusuke Konishi's avatar
Ryusuke Konishi committed
485
	list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) {
486
		res = nilfs_segbuf_submit_bh(segbuf, &wi, bh, rw);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
487
488
489
490
491
		if (unlikely(res))
			goto failed_bio;
	}

	list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {
492
		res = nilfs_segbuf_submit_bh(segbuf, &wi, bh, rw);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
493
494
495
496
		if (unlikely(res))
			goto failed_bio;
	}

497
	if (wi.bio) {
Ryusuke Konishi's avatar
Ryusuke Konishi committed
498
499
500
501
		/*
		 * Last BIO is always sent through the following
		 * submission.
		 */
Jens Axboe's avatar
Jens Axboe committed
502
		rw |= REQ_SYNC;
503
		res = nilfs_segbuf_submit_bio(segbuf, &wi, rw);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
504
505
506
	}

 failed_bio:
507
	return res;
Ryusuke Konishi's avatar
Ryusuke Konishi committed
508
509
510
511
}

/**
 * nilfs_segbuf_wait - wait for completion of requested BIOs
512
 * @segbuf: segment buffer
Ryusuke Konishi's avatar
Ryusuke Konishi committed
513
514
515
516
517
518
 *
 * Return Value: On Success, 0 is returned. On Error, one of the following
 * negative error code is returned.
 *
 * %-EIO - I/O error
 */
519
static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
520
521
522
{
	int err = 0;

523
	if (!segbuf->sb_nbio)
Ryusuke Konishi's avatar
Ryusuke Konishi committed
524
525
526
		return 0;

	do {
527
528
		wait_for_completion(&segbuf->sb_bio_event);
	} while (--segbuf->sb_nbio > 0);
Ryusuke Konishi's avatar
Ryusuke Konishi committed
529

530
	if (unlikely(atomic_read(&segbuf->sb_err) > 0)) {
Ryusuke Konishi's avatar
Ryusuke Konishi committed
531
532
533
534
535
		printk(KERN_ERR "NILFS: IO error writing segment\n");
		err = -EIO;
	}
	return err;
}