inode.c 10.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
/*
 *   Copyright (C) International Business Machines Corp., 2000-2004
 *   Portions Copyright (C) Christoph Hellwig, 2001-2002
 *
 *   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
Dave Kleikamp's avatar
Dave Kleikamp committed
7
 *   the Free Software Foundation; either version 2 of the License, or
Linus Torvalds's avatar
Linus Torvalds committed
8
 *   (at your option) any later version.
Dave Kleikamp's avatar
Dave Kleikamp committed
9
 *
Linus Torvalds's avatar
Linus Torvalds committed
10
11
12
13
14
15
 *   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
Dave Kleikamp's avatar
Dave Kleikamp committed
16
 *   along with this program;  if not, write to the Free Software
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
20
21
22
23
24
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
#include <linux/mpage.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
25
#include <linux/writeback.h>
Linus Torvalds's avatar
Linus Torvalds committed
26
#include "jfs_incore.h"
27
#include "jfs_inode.h"
Linus Torvalds's avatar
Linus Torvalds committed
28
29
30
31
32
33
34
#include "jfs_filsys.h"
#include "jfs_imap.h"
#include "jfs_extent.h"
#include "jfs_unicode.h"
#include "jfs_debug.h"


35
struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds's avatar
Linus Torvalds committed
36
{
37
38
39
40
41
42
43
44
45
46
47
48
49
	struct inode *inode;
	int ret;

	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

	ret = diRead(inode);
	if (ret < 0) {
		iget_failed(inode);
		return ERR_PTR(ret);
Linus Torvalds's avatar
Linus Torvalds committed
50
51
52
53
54
55
56
57
58
59
60
61
62
	}

	if (S_ISREG(inode->i_mode)) {
		inode->i_op = &jfs_file_inode_operations;
		inode->i_fop = &jfs_file_operations;
		inode->i_mapping->a_ops = &jfs_aops;
	} else if (S_ISDIR(inode->i_mode)) {
		inode->i_op = &jfs_dir_inode_operations;
		inode->i_fop = &jfs_dir_operations;
	} else if (S_ISLNK(inode->i_mode)) {
		if (inode->i_size >= IDATASIZE) {
			inode->i_op = &page_symlink_inode_operations;
			inode->i_mapping->a_ops = &jfs_aops;
63
		} else {
64
			inode->i_op = &jfs_fast_symlink_inode_operations;
65
66
67
68
69
70
			/*
			 * The inline data should be null-terminated, but
			 * don't let on-disk corruption crash the kernel
			 */
			JFS_IP(inode)->i_inline[inode->i_size] = '\0';
		}
Linus Torvalds's avatar
Linus Torvalds committed
71
72
73
74
	} else {
		inode->i_op = &jfs_file_inode_operations;
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
	}
75
76
	unlock_new_inode(inode);
	return inode;
Linus Torvalds's avatar
Linus Torvalds committed
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
}

/*
 * Workhorse of both fsync & write_inode
 */
int jfs_commit_inode(struct inode *inode, int wait)
{
	int rc = 0;
	tid_t tid;
	static int noisy = 5;

	jfs_info("In jfs_commit_inode, inode = 0x%p", inode);

	/*
	 * Don't commit if inode has been committed since last being
	 * marked dirty, or if it has been deleted.
	 */
	if (inode->i_nlink == 0 || !test_cflag(COMMIT_Dirty, inode))
		return 0;

	if (isReadOnly(inode)) {
		/* kernel allows writes to devices on read-only
		 * partitions and may think inode is dirty
		 */
		if (!special_file(inode->i_mode) && noisy) {
			jfs_err("jfs_commit_inode(0x%p) called on "
				   "read-only volume", inode);
			jfs_err("Is remount racy?");
			noisy--;
		}
		return 0;
	}

	tid = txBegin(inode->i_sb, COMMIT_INODE);
111
	mutex_lock(&JFS_IP(inode)->commit_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
112
113

	/*
114
	 * Retest inode state after taking commit_mutex
Linus Torvalds's avatar
Linus Torvalds committed
115
116
117
118
119
	 */
	if (inode->i_nlink && test_cflag(COMMIT_Dirty, inode))
		rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);

	txEnd(tid);
120
	mutex_unlock(&JFS_IP(inode)->commit_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
121
122
123
	return rc;
}

124
int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)
Linus Torvalds's avatar
Linus Torvalds committed
125
{
126
127
	int wait = wbc->sync_mode == WB_SYNC_ALL;

Dave Kleikamp's avatar
Dave Kleikamp committed
128
	if (inode->i_nlink == 0)
Linus Torvalds's avatar
Linus Torvalds committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
		return 0;
	/*
	 * If COMMIT_DIRTY is not set, the inode isn't really dirty.
	 * It has been committed since the last change, but was still
	 * on the dirty inode list.
	 */
	 if (!test_cflag(COMMIT_Dirty, inode)) {
		/* Make sure committed changes hit the disk */
		jfs_flush_journal(JFS_SBI(inode->i_sb)->log, wait);
		return 0;
	 }

	if (jfs_commit_inode(inode, wait)) {
		jfs_err("jfs_write_inode: jfs_commit_inode failed!");
		return -EIO;
	} else
		return 0;
}

Al Viro's avatar
Al Viro committed
148
void jfs_evict_inode(struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
149
{
Al Viro's avatar
Al Viro committed
150
	jfs_info("In jfs_evict_inode, inode = 0x%p", inode);
Linus Torvalds's avatar
Linus Torvalds committed
151

Al Viro's avatar
Al Viro committed
152
	if (!inode->i_nlink && !is_bad_inode(inode)) {
153
		dquot_initialize(inode);
154

Al Viro's avatar
Al Viro committed
155
156
		if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
			truncate_inode_pages(&inode->i_data, 0);
157

Al Viro's avatar
Al Viro committed
158
159
			if (test_cflag(COMMIT_Freewmap, inode))
				jfs_free_zero_link(inode);
Linus Torvalds's avatar
Linus Torvalds committed
160

Al Viro's avatar
Al Viro committed
161
			diFree(inode);
Linus Torvalds's avatar
Linus Torvalds committed
162

Al Viro's avatar
Al Viro committed
163
164
165
166
167
168
169
170
			/*
			 * Free the inode from the quota allocation.
			 */
			dquot_initialize(inode);
			dquot_free_inode(inode);
		}
	} else {
		truncate_inode_pages(&inode->i_data, 0);
171
	}
172
	clear_inode(inode);
Al Viro's avatar
Al Viro committed
173
	dquot_drop(inode);
Linus Torvalds's avatar
Linus Torvalds committed
174
175
}

176
void jfs_dirty_inode(struct inode *inode, int flags)
Linus Torvalds's avatar
Linus Torvalds committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
{
	static int noisy = 5;

	if (isReadOnly(inode)) {
		if (!special_file(inode->i_mode) && noisy) {
			/* kernel allows writes to devices on read-only
			 * partitions and may try to mark inode dirty
			 */
			jfs_err("jfs_dirty_inode called on read-only volume");
			jfs_err("Is remount racy?");
			noisy--;
		}
		return;
	}

	set_cflag(COMMIT_Dirty, inode);
}

195
196
int jfs_get_block(struct inode *ip, sector_t lblock,
		  struct buffer_head *bh_result, int create)
Linus Torvalds's avatar
Linus Torvalds committed
197
198
199
200
201
202
{
	s64 lblock64 = lblock;
	int rc = 0;
	xad_t xad;
	s64 xaddr;
	int xflag;
203
	s32 xlen = bh_result->b_size >> ip->i_blkbits;
Linus Torvalds's avatar
Linus Torvalds committed
204
205
206
207

	/*
	 * Take appropriate lock on inode
	 */
208
	if (create)
Dave Kleikamp's avatar
Dave Kleikamp committed
209
		IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
210
	else
Dave Kleikamp's avatar
Dave Kleikamp committed
211
		IREAD_LOCK(ip, RDWRLOCK_NORMAL);
Linus Torvalds's avatar
Linus Torvalds committed
212
213

	if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
214
	    (!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) &&
215
	    xaddr) {
Linus Torvalds's avatar
Linus Torvalds committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
		if (xflag & XAD_NOTRECORDED) {
			if (!create)
				/*
				 * Allocated but not recorded, read treats
				 * this as a hole
				 */
				goto unlock;
#ifdef _JFS_4K
			XADoffset(&xad, lblock64);
			XADlength(&xad, xlen);
			XADaddress(&xad, xaddr);
#else				/* _JFS_4K */
			/*
			 * As long as block size = 4K, this isn't a problem.
			 * We should mark the whole page not ABNR, but how
			 * will we know to mark the other blocks BH_New?
			 */
			BUG();
#endif				/* _JFS_4K */
			rc = extRecord(ip, &xad);
			if (rc)
				goto unlock;
			set_buffer_new(bh_result);
		}

		map_bh(bh_result, ip->i_sb, xaddr);
		bh_result->b_size = xlen << ip->i_blkbits;
		goto unlock;
	}
	if (!create)
		goto unlock;

	/*
	 * Allocate a new block
	 */
#ifdef _JFS_4K
	if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
		goto unlock;
254
	rc = extAlloc(ip, xlen, lblock64, &xad, false);
Linus Torvalds's avatar
Linus Torvalds committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
	if (rc)
		goto unlock;

	set_buffer_new(bh_result);
	map_bh(bh_result, ip->i_sb, addressXAD(&xad));
	bh_result->b_size = lengthXAD(&xad) << ip->i_blkbits;

#else				/* _JFS_4K */
	/*
	 * We need to do whatever it takes to keep all but the last buffers
	 * in 4K pages - see jfs_write.c
	 */
	BUG();
#endif				/* _JFS_4K */

      unlock:
	/*
	 * Release lock on inode
	 */
274
275
276
277
	if (create)
		IWRITE_UNLOCK(ip);
	else
		IREAD_UNLOCK(ip);
Linus Torvalds's avatar
Linus Torvalds committed
278
279
280
281
282
	return rc;
}

static int jfs_writepage(struct page *page, struct writeback_control *wbc)
{
Nick Piggin's avatar
Nick Piggin committed
283
	return block_write_full_page(page, jfs_get_block, wbc);
Linus Torvalds's avatar
Linus Torvalds committed
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
}

static int jfs_writepages(struct address_space *mapping,
			struct writeback_control *wbc)
{
	return mpage_writepages(mapping, wbc, jfs_get_block);
}

static int jfs_readpage(struct file *file, struct page *page)
{
	return mpage_readpage(page, jfs_get_block);
}

static int jfs_readpages(struct file *file, struct address_space *mapping,
		struct list_head *pages, unsigned nr_pages)
{
	return mpage_readpages(mapping, pages, nr_pages, jfs_get_block);
}

Marco Stornelli's avatar
Marco Stornelli committed
303
304
305
306
307
308
309
310
311
312
static void jfs_write_failed(struct address_space *mapping, loff_t to)
{
	struct inode *inode = mapping->host;

	if (to > inode->i_size) {
		truncate_pagecache(inode, to, inode->i_size);
		jfs_truncate(inode);
	}
}

Nick Piggin's avatar
Nick Piggin committed
313
314
315
static int jfs_write_begin(struct file *file, struct address_space *mapping,
				loff_t pos, unsigned len, unsigned flags,
				struct page **pagep, void **fsdata)
Linus Torvalds's avatar
Linus Torvalds committed
316
{
317
318
319
	int ret;

	ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
Nick Piggin's avatar
Nick Piggin committed
320
				jfs_get_block);
Marco Stornelli's avatar
Marco Stornelli committed
321
322
	if (unlikely(ret))
		jfs_write_failed(mapping, pos + len);
323
324

	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
325
326
327
328
329
330
331
332
333
334
335
}

static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
{
	return generic_block_bmap(mapping, block, jfs_get_block);
}

static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
	const struct iovec *iov, loff_t offset, unsigned long nr_segs)
{
	struct file *file = iocb->ki_filp;
Marco Stornelli's avatar
Marco Stornelli committed
336
	struct address_space *mapping = file->f_mapping;
Linus Torvalds's avatar
Linus Torvalds committed
337
	struct inode *inode = file->f_mapping->host;
338
	ssize_t ret;
Linus Torvalds's avatar
Linus Torvalds committed
339

340
341
	ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
				 jfs_get_block);
342
343
344
345
346
347
348
349
350
351

	/*
	 * In case of error extending write may have instantiated a few
	 * blocks outside i_size. Trim these off again.
	 */
	if (unlikely((rw & WRITE) && ret < 0)) {
		loff_t isize = i_size_read(inode);
		loff_t end = offset + iov_length(iov, nr_segs);

		if (end > isize)
Marco Stornelli's avatar
Marco Stornelli committed
352
			jfs_write_failed(mapping, end);
353
354
355
	}

	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
356
357
}

358
const struct address_space_operations jfs_aops = {
Linus Torvalds's avatar
Linus Torvalds committed
359
360
361
362
	.readpage	= jfs_readpage,
	.readpages	= jfs_readpages,
	.writepage	= jfs_writepage,
	.writepages	= jfs_writepages,
Nick Piggin's avatar
Nick Piggin committed
363
	.write_begin	= jfs_write_begin,
Nick Piggin's avatar
Nick Piggin committed
364
	.write_end	= nobh_write_end,
Linus Torvalds's avatar
Linus Torvalds committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	.bmap		= jfs_bmap,
	.direct_IO	= jfs_direct_IO,
};

/*
 * Guts of jfs_truncate.  Called with locks already held.  Can be called
 * with directory for truncating directory index table.
 */
void jfs_truncate_nolock(struct inode *ip, loff_t length)
{
	loff_t newsize;
	tid_t tid;

	ASSERT(length >= 0);

	if (test_cflag(COMMIT_Nolink, ip)) {
		xtTruncate(0, ip, length, COMMIT_WMAP);
		return;
	}

	do {
		tid = txBegin(ip->i_sb, 0);

		/*
389
		 * The commit_mutex cannot be taken before txBegin.
Linus Torvalds's avatar
Linus Torvalds committed
390
391
392
393
		 * txBegin may block and there is a chance the inode
		 * could be marked dirty and need to be committed
		 * before txBegin unblocks
		 */
394
		mutex_lock(&JFS_IP(ip)->commit_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
395
396
397
398
399

		newsize = xtTruncate(tid, ip, length,
				     COMMIT_TRUNCATE | COMMIT_PWMAP);
		if (newsize < 0) {
			txEnd(tid);
400
			mutex_unlock(&JFS_IP(ip)->commit_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
401
402
403
404
405
406
407
408
			break;
		}

		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
		mark_inode_dirty(ip);

		txCommit(tid, 1, &ip, 0);
		txEnd(tid);
409
		mutex_unlock(&JFS_IP(ip)->commit_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
410
411
412
413
414
415
416
	} while (newsize > length);	/* Truncate isn't always atomic */
}

void jfs_truncate(struct inode *ip)
{
	jfs_info("jfs_truncate: size = 0x%lx", (ulong) ip->i_size);

Nick Piggin's avatar
Nick Piggin committed
417
	nobh_truncate_page(ip->i_mapping, ip->i_size, jfs_get_block);
Linus Torvalds's avatar
Linus Torvalds committed
418

Dave Kleikamp's avatar
Dave Kleikamp committed
419
	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
Linus Torvalds's avatar
Linus Torvalds committed
420
421
422
	jfs_truncate_nolock(ip, ip->i_size);
	IWRITE_UNLOCK(ip);
}