file.c 9.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
4
 * Copyright © 2001-2007 Red Hat, Inc.
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * Created by David Woodhouse <dwmw2@infradead.org>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/crc32.h>
#include <linux/jffs2.h>
#include "nodelist.h"

N
Nick Piggin 已提交
22 23 24 25 26 27
static int jffs2_write_end(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *pg, void *fsdata);
static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata);
L
Linus Torvalds 已提交
28 29 30 31 32 33 34 35 36
static int jffs2_readpage (struct file *filp, struct page *pg);

int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
{
	struct inode *inode = dentry->d_inode;
	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);

	/* Trigger GC to flush any pending writes for this inode */
	jffs2_flush_wbuf_gc(c, inode->i_ino);
37 38

	return 0;
L
Linus Torvalds 已提交
39 40
}

41
const struct file_operations jffs2_file_operations =
L
Linus Torvalds 已提交
42 43 44
{
	.llseek =	generic_file_llseek,
	.open =		generic_file_open,
45 46 47 48
 	.read =		do_sync_read,
 	.aio_read =	generic_file_aio_read,
 	.write =	do_sync_write,
 	.aio_write =	generic_file_aio_write,
L
Linus Torvalds 已提交
49 50 51
	.ioctl =	jffs2_ioctl,
	.mmap =		generic_file_readonly_mmap,
	.fsync =	jffs2_fsync,
52
	.splice_read =	generic_file_splice_read,
L
Linus Torvalds 已提交
53 54 55 56
};

/* jffs2_file_inode_operations */

57
const struct inode_operations jffs2_file_inode_operations =
L
Linus Torvalds 已提交
58
{
59 60 61 62 63 64
	.permission =	jffs2_permission,
	.setattr =	jffs2_setattr,
	.setxattr =	jffs2_setxattr,
	.getxattr =	jffs2_getxattr,
	.listxattr =	jffs2_listxattr,
	.removexattr =	jffs2_removexattr
L
Linus Torvalds 已提交
65 66
};

67
const struct address_space_operations jffs2_file_address_operations =
L
Linus Torvalds 已提交
68 69
{
	.readpage =	jffs2_readpage,
N
Nick Piggin 已提交
70 71
	.write_begin =	jffs2_write_begin,
	.write_end =	jffs2_write_end,
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82
};

static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
{
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
	unsigned char *pg_buf;
	int ret;

	D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));

M
Matt Mackall 已提交
83
	BUG_ON(!PageLocked(pg));
L
Linus Torvalds 已提交
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 111 112 113 114 115 116

	pg_buf = kmap(pg);
	/* FIXME: Can kmap fail? */

	ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);

	if (ret) {
		ClearPageUptodate(pg);
		SetPageError(pg);
	} else {
		SetPageUptodate(pg);
		ClearPageError(pg);
	}

	flush_dcache_page(pg);
	kunmap(pg);

	D2(printk(KERN_DEBUG "readpage finished\n"));
	return 0;
}

int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
{
	int ret = jffs2_do_readpage_nolock(inode, pg);
	unlock_page(pg);
	return ret;
}


static int jffs2_readpage (struct file *filp, struct page *pg)
{
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
	int ret;
117

L
Linus Torvalds 已提交
118 119 120 121 122 123
	down(&f->sem);
	ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
	up(&f->sem);
	return ret;
}

N
Nick Piggin 已提交
124 125 126
static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
L
Linus Torvalds 已提交
127
{
N
Nick Piggin 已提交
128 129
	struct page *pg;
	struct inode *inode = mapping->host;
L
Linus Torvalds 已提交
130
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
N
Nick Piggin 已提交
131 132
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
	uint32_t pageofs = pos & (PAGE_CACHE_SIZE - 1);
L
Linus Torvalds 已提交
133 134
	int ret = 0;

N
Nick Piggin 已提交
135 136 137 138 139 140
	pg = __grab_cache_page(mapping, index);
	if (!pg)
		return -ENOMEM;
	*pagep = pg;

	D1(printk(KERN_DEBUG "jffs2_write_begin()\n"));
L
Linus Torvalds 已提交
141 142 143 144 145 146

	if (pageofs > inode->i_size) {
		/* Make new hole frag from old EOF to new page */
		struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
		struct jffs2_raw_inode ri;
		struct jffs2_full_dnode *fn;
147
		uint32_t alloc_len;
148

L
Linus Torvalds 已提交
149 150 151
		D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
			  (unsigned int)inode->i_size, pageofs));

152 153
		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
L
Linus Torvalds 已提交
154
		if (ret)
N
Nick Piggin 已提交
155
			goto out_page;
L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

		down(&f->sem);
		memset(&ri, 0, sizeof(ri));

		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
		ri.totlen = cpu_to_je32(sizeof(ri));
		ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));

		ri.ino = cpu_to_je32(f->inocache->ino);
		ri.version = cpu_to_je32(++f->highest_version);
		ri.mode = cpu_to_jemode(inode->i_mode);
		ri.uid = cpu_to_je16(inode->i_uid);
		ri.gid = cpu_to_je16(inode->i_gid);
		ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
		ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds());
		ri.offset = cpu_to_je32(inode->i_size);
		ri.dsize = cpu_to_je32(pageofs - inode->i_size);
		ri.csize = cpu_to_je32(0);
		ri.compr = JFFS2_COMPR_ZERO;
		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
		ri.data_crc = cpu_to_je32(0);
178

179
		fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL);
L
Linus Torvalds 已提交
180 181 182 183 184

		if (IS_ERR(fn)) {
			ret = PTR_ERR(fn);
			jffs2_complete_reservation(c);
			up(&f->sem);
N
Nick Piggin 已提交
185
			goto out_page;
L
Linus Torvalds 已提交
186 187 188 189 190 191 192 193
		}
		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
		if (f->metadata) {
			jffs2_mark_node_obsolete(c, f->metadata->raw);
			jffs2_free_full_dnode(f->metadata);
			f->metadata = NULL;
		}
		if (ret) {
N
Nick Piggin 已提交
194
			D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n", ret));
L
Linus Torvalds 已提交
195 196 197 198
			jffs2_mark_node_obsolete(c, fn->raw);
			jffs2_free_full_dnode(fn);
			jffs2_complete_reservation(c);
			up(&f->sem);
N
Nick Piggin 已提交
199
			goto out_page;
L
Linus Torvalds 已提交
200 201 202 203 204
		}
		jffs2_complete_reservation(c);
		inode->i_size = pageofs;
		up(&f->sem);
	}
205

N
Nick Piggin 已提交
206 207 208 209 210 211
	/*
	 * Read in the page if it wasn't already present. Cannot optimize away
	 * the whole page write case until jffs2_write_end can handle the
	 * case of a short-copy.
	 */
	if (!PageUptodate(pg)) {
L
Linus Torvalds 已提交
212 213 214
		down(&f->sem);
		ret = jffs2_do_readpage_nolock(inode, pg);
		up(&f->sem);
N
Nick Piggin 已提交
215 216
		if (ret)
			goto out_page;
L
Linus Torvalds 已提交
217
	}
N
Nick Piggin 已提交
218 219 220 221 222 223
	D1(printk(KERN_DEBUG "end write_begin(). pg->flags %lx\n", pg->flags));
	return ret;

out_page:
	unlock_page(pg);
	page_cache_release(pg);
L
Linus Torvalds 已提交
224 225 226
	return ret;
}

N
Nick Piggin 已提交
227 228 229
static int jffs2_write_end(struct file *filp, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *pg, void *fsdata)
L
Linus Torvalds 已提交
230 231 232 233
{
	/* Actually commit the write from the page cache page we're looking at.
	 * For now, we write the full page out each time. It sucks, but it's simple
	 */
N
Nick Piggin 已提交
234
	struct inode *inode = mapping->host;
L
Linus Torvalds 已提交
235 236 237
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
	struct jffs2_raw_inode *ri;
N
Nick Piggin 已提交
238 239
	unsigned start = pos & (PAGE_CACHE_SIZE - 1);
	unsigned end = start + copied;
L
Linus Torvalds 已提交
240 241 242 243
	unsigned aligned_start = start & ~3;
	int ret = 0;
	uint32_t writtenlen = 0;

N
Nick Piggin 已提交
244
	D1(printk(KERN_DEBUG "jffs2_write_end(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
L
Linus Torvalds 已提交
245 246
		  inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));

N
Nick Piggin 已提交
247 248 249 250 251 252
	/* We need to avoid deadlock with page_cache_read() in
	   jffs2_garbage_collect_pass(). So the page must be
	   up to date to prevent page_cache_read() from trying
	   to re-lock it. */
	BUG_ON(!PageUptodate(pg));

253
	if (end == PAGE_CACHE_SIZE) {
N
Nick Piggin 已提交
254 255 256 257 258
		/* When writing out the end of a page, write out the
		   _whole_ page. This helps to reduce the number of
		   nodes in files which have many short writes, like
		   syslog files. */
		start = aligned_start = 0;
L
Linus Torvalds 已提交
259 260 261 262 263
	}

	ri = jffs2_alloc_raw_inode();

	if (!ri) {
N
Nick Piggin 已提交
264 265 266
		D1(printk(KERN_DEBUG "jffs2_write_end(): Allocation of raw inode failed\n"));
		unlock_page(pg);
		page_cache_release(pg);
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
		return -ENOMEM;
	}

	/* Set the fields that the generic jffs2_write_inode_range() code can't find */
	ri->ino = cpu_to_je32(inode->i_ino);
	ri->mode = cpu_to_jemode(inode->i_mode);
	ri->uid = cpu_to_je16(inode->i_uid);
	ri->gid = cpu_to_je16(inode->i_gid);
	ri->isize = cpu_to_je32((uint32_t)inode->i_size);
	ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds());

	/* In 2.4, it was already kmapped by generic_file_write(). Doesn't
	   hurt to do it again. The alternative is ifdefs, which are ugly. */
	kmap(pg);

	ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
				      (pg->index << PAGE_CACHE_SHIFT) + aligned_start,
				      end - aligned_start, &writtenlen);

	kunmap(pg);

	if (ret) {
		/* There was an error writing. */
		SetPageError(pg);
	}
292

L
Linus Torvalds 已提交
293 294 295 296 297 298 299 300 301 302
	/* Adjust writtenlen for the padding we did, so we don't confuse our caller */
	if (writtenlen < (start&3))
		writtenlen = 0;
	else
		writtenlen -= (start&3);

	if (writtenlen) {
		if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
			inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
			inode->i_blocks = (inode->i_size + 511) >> 9;
303

L
Linus Torvalds 已提交
304 305 306 307 308 309 310 311
			inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
		}
	}

	jffs2_free_raw_inode(ri);

	if (start+writtenlen < end) {
		/* generic_file_write has written more to the page cache than we've
312
		   actually written to the medium. Mark the page !Uptodate so that
L
Linus Torvalds 已提交
313
		   it gets reread */
N
Nick Piggin 已提交
314
		D1(printk(KERN_DEBUG "jffs2_write_end(): Not all bytes written. Marking page !uptodate\n"));
L
Linus Torvalds 已提交
315 316 317 318
		SetPageError(pg);
		ClearPageUptodate(pg);
	}

N
Nick Piggin 已提交
319 320 321 322 323
	D1(printk(KERN_DEBUG "jffs2_write_end() returning %d\n",
					writtenlen > 0 ? writtenlen : ret));
	unlock_page(pg);
	page_cache_release(pg);
	return writtenlen > 0 ? writtenlen : ret;
L
Linus Torvalds 已提交
324
}