Blame view

fs/jffs2/fs.c 19.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * JFFS2 -- Journalling Flash File System, Version 2.
   *
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
4
   * Copyright © 2001-2007 Red Hat, Inc.
6088c0587   David Woodhouse   jffs2: Update cop...
5
   * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
   *
   * Created by David Woodhouse <dwmw2@infradead.org>
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
   */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
12
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
21
22
23
24
25
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/fs.h>
  #include <linux/list.h>
  #include <linux/mtd/mtd.h>
  #include <linux/pagemap.h>
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
  #include <linux/vfs.h>
  #include <linux/crc32.h>
  #include "nodelist.h"
  
  static int jffs2_flash_setup(struct jffs2_sb_info *c);
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
26
  int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
  {
  	struct jffs2_full_dnode *old_metadata, *new_metadata;
  	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;
aef9ab478   David Woodhouse   [JFFS2] Support n...
32
  	union jffs2_device_node dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  	unsigned char *mdata = NULL;
  	int mdatalen = 0;
  	unsigned int ivalid;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
36
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  	int ret;
dd919660a   David Woodhouse   [JFFS2] Use ALLOC...
38
  	int alloc_type = ALLOC_NORMAL;
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
39

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  	D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu
  ", inode->i_ino));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
  
  	/* Special cases - we don't want more than one data node
  	   for these types on the medium at any time. So setattr
  	   must read the original data associated with the node
  	   (i.e. the device numbers or the target name) and write
  	   it out again with the appropriate data attached */
  	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
  		/* For these, we don't actually need to read the old node */
aef9ab478   David Woodhouse   [JFFS2] Support n...
50
  		mdatalen = jffs2_encode_dev(&dev, inode->i_rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  		mdata = (char *)&dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t
  ", mdatalen));
  	} else if (S_ISLNK(inode->i_mode)) {
ced220703   David Woodhouse   [JFFS2] semaphore...
55
  		mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  		mdatalen = f->metadata->size;
  		mdata = kmalloc(f->metadata->size, GFP_USER);
422138dd6   Dmitry Bazhenov   [JFFS2] Fix race ...
58
  		if (!mdata) {
ced220703   David Woodhouse   [JFFS2] semaphore...
59
  			mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  			return -ENOMEM;
422138dd6   Dmitry Bazhenov   [JFFS2] Fix race ...
61
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  		ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
  		if (ret) {
ced220703   David Woodhouse   [JFFS2] semaphore...
64
  			mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
  			kfree(mdata);
  			return ret;
  		}
ced220703   David Woodhouse   [JFFS2] semaphore...
68
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
77
78
  		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target
  ", mdatalen));
  	}
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri) {
  		if (S_ISLNK(inode->i_mode))
  			kfree(mdata);
  		return -ENOMEM;
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
79

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
80
81
  	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  	if (ret) {
  		jffs2_free_raw_inode(ri);
61effb519   Al Viro   jffs2: S_ISLNK(mo...
84
  		if (S_ISLNK(inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
  			 kfree(mdata);
  		return ret;
  	}
ced220703   David Woodhouse   [JFFS2] semaphore...
88
  	mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	ivalid = iattr->ia_valid;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
90

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
  	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
  	ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
  	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
  
  	ri->ino = cpu_to_je32(inode->i_ino);
  	ri->version = cpu_to_je32(++f->highest_version);
  
  	ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
  	ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
  
  	if (ivalid & ATTR_MODE)
857013b87   David Woodhouse   [JFFS2] Don't str...
103
  		ri->mode = cpu_to_jemode(iattr->ia_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	else
  		ri->mode = cpu_to_jemode(inode->i_mode);
  
  
  	ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
  	ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
  	ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
  	ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
  
  	ri->offset = cpu_to_je32(0);
  	ri->csize = ri->dsize = cpu_to_je32(mdatalen);
  	ri->compr = JFFS2_COMPR_NONE;
  	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
  		/* It's an extension. Make it a hole node */
  		ri->compr = JFFS2_COMPR_ZERO;
  		ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
  		ri->offset = cpu_to_je32(inode->i_size);
dd919660a   David Woodhouse   [JFFS2] Use ALLOC...
121
122
123
124
  	} else if (ivalid & ATTR_SIZE && !iattr->ia_size) {
  		/* For truncate-to-zero, treat it as deletion because
  		   it'll always be obsoleting all previous nodes */
  		alloc_type = ALLOC_DELETION;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
  	}
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
  	if (mdatalen)
  		ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
  	else
  		ri->data_crc = cpu_to_je32(0);
dd919660a   David Woodhouse   [JFFS2] Use ALLOC...
131
  	new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
  	if (S_ISLNK(inode->i_mode))
  		kfree(mdata);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
  	if (IS_ERR(new_metadata)) {
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_inode(ri);
ced220703   David Woodhouse   [JFFS2] semaphore...
138
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  		return PTR_ERR(new_metadata);
  	}
  	/* It worked. Update the inode */
  	inode->i_atime = ITIME(je32_to_cpu(ri->atime));
  	inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
  	inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
  	inode->i_mode = jemode_to_cpu(ri->mode);
  	inode->i_uid = je16_to_cpu(ri->uid);
  	inode->i_gid = je16_to_cpu(ri->gid);
  
  
  	old_metadata = f->metadata;
  
  	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
f302cd028   Artem B. Bityutskiy   [JFFS2] Namespace...
153
  		jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
  
  	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
  		jffs2_add_full_dnode_to_inode(c, f, new_metadata);
  		inode->i_size = iattr->ia_size;
b28ba9fa0   David Woodhouse   [JFFS2] Set i_blo...
158
  		inode->i_blocks = (inode->i_size + 511) >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
164
165
166
167
  		f->metadata = NULL;
  	} else {
  		f->metadata = new_metadata;
  	}
  	if (old_metadata) {
  		jffs2_mark_node_obsolete(c, old_metadata->raw);
  		jffs2_free_full_dnode(old_metadata);
  	}
  	jffs2_free_raw_inode(ri);
ced220703   David Woodhouse   [JFFS2] semaphore...
168
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	jffs2_complete_reservation(c);
2c27c65ed   Christoph Hellwig   check ATTR_SIZE c...
170
  	/* We have to do the truncate_setsize() without f->sem held, since
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
171
  	   some pages may be locked and waiting for it in readpage().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
  	   We are protected from a simultaneous write() extending i_size
  	   back past iattr->ia_size, because do_truncate() holds the
  	   generic inode semaphore. */
b28ba9fa0   David Woodhouse   [JFFS2] Set i_blo...
175
  	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
2c27c65ed   Christoph Hellwig   check ATTR_SIZE c...
176
  		truncate_setsize(inode, iattr->ia_size);
b28ba9fa0   David Woodhouse   [JFFS2] Set i_blo...
177
178
  		inode->i_blocks = (inode->i_size + 511) >> 9;
  	}	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
  
  	return 0;
  }
  
  int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
  {
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
185
  	int rc;
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
186
187
188
  	rc = inode_change_ok(dentry->d_inode, iattr);
  	if (rc)
  		return rc;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
189
190
191
  	rc = jffs2_do_setattr(dentry->d_inode, iattr);
  	if (!rc && (iattr->ia_valid & ATTR_MODE))
  		rc = jffs2_acl_chmod(dentry->d_inode);
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
192

aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
193
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  }
726c33422   David Howells   [PATCH] VFS: Perm...
195
  int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  {
726c33422   David Howells   [PATCH] VFS: Perm...
197
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
  	unsigned long avail;
  
  	buf->f_type = JFFS2_SUPER_MAGIC;
  	buf->f_bsize = 1 << PAGE_SHIFT;
  	buf->f_blocks = c->flash_size >> PAGE_SHIFT;
  	buf->f_files = 0;
  	buf->f_ffree = 0;
  	buf->f_namelen = JFFS2_MAX_NAME_LEN;
75caf6b5a   David Woodhouse   [JFFS2] Fill in f...
206
207
  	buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC;
  	buf->f_fsid.val[1] = c->mtd->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  
  	spin_lock(&c->erase_completion_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
  	avail = c->dirty_size + c->free_size;
  	if (avail > c->sector_size * c->resv_blocks_write)
  		avail -= c->sector_size * c->resv_blocks_write;
  	else
  		avail = 0;
e0c8e42f8   Artem B. Bityutskiy   [JFFS2] Debug cod...
215
  	spin_unlock(&c->erase_completion_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  
  	buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  	return 0;
  }
b57922d97   Al Viro   convert remaining...
220
  void jffs2_evict_inode (struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
222
  	/* We can forget about this inode for now - drop all
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
  	 *  the nodelists associated with it, etc.
  	 */
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
227

b57922d97   Al Viro   convert remaining...
228
229
230
231
  	D1(printk(KERN_DEBUG "jffs2_evict_inode(): ino #%lu mode %o
  ", inode->i_ino, inode->i_mode));
  	truncate_inode_pages(&inode->i_data, 0);
  	end_writeback(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
  	jffs2_do_clear_inode(c, f);
  }
5451f79f5   David Howells   iget: stop JFFS2 ...
234
  struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
  {
  	struct jffs2_inode_info *f;
  	struct jffs2_sb_info *c;
  	struct jffs2_raw_inode latest_node;
aef9ab478   David Woodhouse   [JFFS2] Support n...
239
  	union jffs2_device_node jdev;
5451f79f5   David Howells   iget: stop JFFS2 ...
240
  	struct inode *inode;
aef9ab478   David Woodhouse   [JFFS2] Support n...
241
  	dev_t rdev = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	int ret;
5451f79f5   David Howells   iget: stop JFFS2 ...
243
244
245
246
247
248
249
250
  	D1(printk(KERN_DEBUG "jffs2_iget(): ino == %lu
  ", ino));
  
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
  
  	f = JFFS2_INODE_INFO(inode);
  	c = JFFS2_SB_INFO(inode->i_sb);
  
  	jffs2_init_inode_info(f);
ced220703   David Woodhouse   [JFFS2] semaphore...
256
  	mutex_lock(&f->sem);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
257

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
  	ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
  
  	if (ret) {
ced220703   David Woodhouse   [JFFS2] semaphore...
261
  		mutex_unlock(&f->sem);
5451f79f5   David Howells   iget: stop JFFS2 ...
262
263
  		iget_failed(inode);
  		return ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
  	}
  	inode->i_mode = jemode_to_cpu(latest_node.mode);
  	inode->i_uid = je16_to_cpu(latest_node.uid);
  	inode->i_gid = je16_to_cpu(latest_node.gid);
  	inode->i_size = je32_to_cpu(latest_node.isize);
  	inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
  	inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
  	inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
bfe868486   Miklos Szeredi   filesystems: add ...
272
  	set_nlink(inode, f->inocache->pino_nlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	inode->i_blocks = (inode->i_size + 511) >> 9;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	switch (inode->i_mode & S_IFMT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
  
  	case S_IFLNK:
  		inode->i_op = &jffs2_symlink_inode_operations;
  		break;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
281

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  	case S_IFDIR:
  	{
  		struct jffs2_full_dirent *fd;
bfe868486   Miklos Szeredi   filesystems: add ...
285
  		set_nlink(inode, 2); /* parent and '.' */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  
  		for (fd=f->dents; fd; fd = fd->next) {
  			if (fd->type == DT_DIR && fd->ino)
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
289
  				inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  		/* Root dir gets i_nlink 3 for some reason */
  		if (inode->i_ino == 1)
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
293
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  
  		inode->i_op = &jffs2_dir_inode_operations;
  		inode->i_fop = &jffs2_dir_operations;
  		break;
  	}
  	case S_IFREG:
  		inode->i_op = &jffs2_file_inode_operations;
  		inode->i_fop = &jffs2_file_operations;
  		inode->i_mapping->a_ops = &jffs2_file_address_operations;
  		inode->i_mapping->nrpages = 0;
  		break;
  
  	case S_IFBLK:
  	case S_IFCHR:
  		/* Read the device numbers from the media */
91f802660   Andrew Morton   JFFS2: avoid usin...
309
310
  		if (f->metadata->size != sizeof(jdev.old_id) &&
  		    f->metadata->size != sizeof(jdev.new_id)) {
aef9ab478   David Woodhouse   [JFFS2] Support n...
311
312
  			printk(KERN_NOTICE "Device node has strange size %d
  ", f->metadata->size);
5451f79f5   David Howells   iget: stop JFFS2 ...
313
  			goto error_io;
aef9ab478   David Woodhouse   [JFFS2] Support n...
314
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  		D1(printk(KERN_DEBUG "Reading device numbers from flash
  "));
5451f79f5   David Howells   iget: stop JFFS2 ...
317
318
  		ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size);
  		if (ret < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
  			/* Eep */
  			printk(KERN_NOTICE "Read device numbers for inode %lu failed
  ", (unsigned long)inode->i_ino);
5451f79f5   David Howells   iget: stop JFFS2 ...
322
  			goto error;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
323
  		}
91f802660   Andrew Morton   JFFS2: avoid usin...
324
325
  		if (f->metadata->size == sizeof(jdev.old_id))
  			rdev = old_decode_dev(je16_to_cpu(jdev.old_id));
aef9ab478   David Woodhouse   [JFFS2] Support n...
326
  		else
91f802660   Andrew Morton   JFFS2: avoid usin...
327
  			rdev = new_decode_dev(je32_to_cpu(jdev.new_id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
  
  	case S_IFSOCK:
  	case S_IFIFO:
  		inode->i_op = &jffs2_file_inode_operations;
aef9ab478   David Woodhouse   [JFFS2] Support n...
332
  		init_special_inode(inode, inode->i_mode, rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
  		break;
  
  	default:
  		printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu
  ", inode->i_mode, (unsigned long)inode->i_ino);
  	}
ced220703   David Woodhouse   [JFFS2] semaphore...
339
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
  
  	D1(printk(KERN_DEBUG "jffs2_read_inode() returning
  "));
5451f79f5   David Howells   iget: stop JFFS2 ...
343
344
345
346
347
348
  	unlock_new_inode(inode);
  	return inode;
  
  error_io:
  	ret = -EIO;
  error:
ced220703   David Woodhouse   [JFFS2] semaphore...
349
  	mutex_unlock(&f->sem);
5451f79f5   David Howells   iget: stop JFFS2 ...
350
351
352
  	jffs2_do_clear_inode(c, f);
  	iget_failed(inode);
  	return ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  }
aa3857295   Christoph Hellwig   fs: pass exact ty...
354
  void jffs2_dirty_inode(struct inode *inode, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  {
  	struct iattr iattr;
  
  	if (!(inode->i_state & I_DIRTY_DATASYNC)) {
  		D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu
  ", inode->i_ino));
  		return;
  	}
  
  	D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu
  ", inode->i_ino));
  
  	iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
  	iattr.ia_mode = inode->i_mode;
  	iattr.ia_uid = inode->i_uid;
  	iattr.ia_gid = inode->i_gid;
  	iattr.ia_atime = inode->i_atime;
  	iattr.ia_mtime = inode->i_mtime;
  	iattr.ia_ctime = inode->i_ctime;
  
  	jffs2_do_setattr(inode, &iattr);
  }
92abc475d   Andres Salomon   jffs2: implement ...
377
  int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
388
389
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
  
  	if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
  		return -EROFS;
  
  	/* We stop if it was running, then restart if it needs to.
  	   This also catches the case where it was stopped and this
  	   is just a remount to restart it.
  	   Flush the writebuffer, if neccecary, else we loose it */
  	if (!(sb->s_flags & MS_RDONLY)) {
  		jffs2_stop_garbage_collect_thread(c);
ced220703   David Woodhouse   [JFFS2] semaphore...
390
  		mutex_lock(&c->alloc_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  		jffs2_flush_wbuf_pad(c);
ced220703   David Woodhouse   [JFFS2] semaphore...
392
  		mutex_unlock(&c->alloc_sem);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
393
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
  
  	if (!(*flags & MS_RDONLY))
  		jffs2_start_garbage_collect_thread(c);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
397

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  	*flags |= MS_NOATIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
  /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
     fill in the raw_inode while you're at it. */
d3fb61207   Al Viro   switch posix_acl_...
403
  struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
408
409
410
411
412
413
414
  {
  	struct inode *inode;
  	struct super_block *sb = dir_i->i_sb;
  	struct jffs2_sb_info *c;
  	struct jffs2_inode_info *f;
  	int ret;
  
  	D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x
  ", dir_i->i_ino, mode));
  
  	c = JFFS2_SB_INFO(sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
415

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  	inode = new_inode(sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
417

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  
  	f = JFFS2_INODE_INFO(inode);
  	jffs2_init_inode_info(f);
ced220703   David Woodhouse   [JFFS2] semaphore...
423
  	mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
  
  	memset(ri, 0, sizeof(*ri));
  	/* Set OS-specific defaults for new inodes */
3fc678a0e   David Howells   CRED: Wrap task c...
427
  	ri->uid = cpu_to_je16(current_fsuid());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
431
432
433
  
  	if (dir_i->i_mode & S_ISGID) {
  		ri->gid = cpu_to_je16(dir_i->i_gid);
  		if (S_ISDIR(mode))
  			mode |= S_ISGID;
  	} else {
3fc678a0e   David Howells   CRED: Wrap task c...
434
  		ri->gid = cpu_to_je16(current_fsgid());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  	}
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
436
437
438
  
  	/* POSIX ACLs have to be processed now, at least partly.
  	   The umask is only applied if there's no default ACL */
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
439
440
441
442
443
  	ret = jffs2_init_acl_pre(dir_i, inode, &mode);
  	if (ret) {
  	    make_bad_inode(inode);
  	    iput(inode);
  	    return ERR_PTR(ret);
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
444
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
  	ret = jffs2_do_new_inode (c, f, mode, ri);
  	if (ret) {
  		make_bad_inode(inode);
  		iput(inode);
  		return ERR_PTR(ret);
  	}
bfe868486   Miklos Szeredi   filesystems: add ...
451
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
457
  	inode->i_ino = je32_to_cpu(ri->ino);
  	inode->i_mode = jemode_to_cpu(ri->mode);
  	inode->i_gid = je16_to_cpu(ri->gid);
  	inode->i_uid = je16_to_cpu(ri->uid);
  	inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
  	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  	inode->i_blocks = 0;
  	inode->i_size = 0;
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
460
461
  	if (insert_inode_locked(inode) < 0) {
  		make_bad_inode(inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
462
463
464
  		iput(inode);
  		return ERR_PTR(-EINVAL);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
  
  	return inode;
  }
65e5a0e18   Daniel Drake   jffs2: Dynamicall...
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  static int calculate_inocache_hashsize(uint32_t flash_size)
  {
  	/*
  	 * Pick a inocache hash size based on the size of the medium.
  	 * Count how many megabytes we're dealing with, apply a hashsize twice
  	 * that size, but rounding down to the usual big powers of 2. And keep
  	 * to sensible bounds.
  	 */
  
  	int size_mb = flash_size / 1024 / 1024;
  	int hashsize = (size_mb * 2) & ~0x3f;
  
  	if (hashsize < INOCACHE_HASHSIZE_MIN)
  		return INOCACHE_HASHSIZE_MIN;
  	if (hashsize > INOCACHE_HASHSIZE_MAX)
  		return INOCACHE_HASHSIZE_MAX;
  
  	return hashsize;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
  
  int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct jffs2_sb_info *c;
  	struct inode *root_i;
  	int ret;
  	size_t blocks;
  
  	c = JFFS2_SB_INFO(sb);
2f82ce1eb   Andrew Victor   [JFFS2] Use a sin...
496
  #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
  	if (c->mtd->type == MTD_NANDFLASH) {
  		printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.
  ");
  		return -EINVAL;
  	}
8f15fd55f   Andrew Victor   [JFFS2] Add suppo...
502
503
504
505
506
507
  	if (c->mtd->type == MTD_DATAFLASH) {
  		printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.
  ");
  		return -EINVAL;
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  
  	c->flash_size = c->mtd->size;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
510
  	c->sector_size = c->mtd->erasesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  	blocks = c->flash_size / c->sector_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
516
  
  	/*
  	 * Size alignment check
  	 */
  	if ((c->sector_size * blocks) != c->flash_size) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
517
  		c->flash_size = c->sector_size * blocks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
  		printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB
  ",
  			c->flash_size / 1024);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
528
  	if (c->flash_size < 5*c->sector_size) {
  		printk(KERN_ERR "jffs2: Too few erase blocks (%d)
  ", c->flash_size / c->sector_size);
  		return -EINVAL;
  	}
  
  	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
  
  	/* NAND (or other bizarre) flash... do setup accordingly */
  	ret = jffs2_flash_setup(c);
  	if (ret)
  		return ret;
65e5a0e18   Daniel Drake   jffs2: Dynamicall...
534
535
  	c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size);
  	c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
  	if (!c->inocache_list) {
  		ret = -ENOMEM;
  		goto out_wbuf;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540

aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
541
  	jffs2_init_xattr_subsystem(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  	if ((ret = jffs2_do_mount_fs(c)))
  		goto out_inohash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode
  "));
5451f79f5   David Howells   iget: stop JFFS2 ...
546
547
  	root_i = jffs2_iget(sb, 1);
  	if (IS_ERR(root_i)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  		D1(printk(KERN_WARNING "get root inode failed
  "));
5451f79f5   David Howells   iget: stop JFFS2 ...
550
551
  		ret = PTR_ERR(root_i);
  		goto out_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  	}
5451f79f5   David Howells   iget: stop JFFS2 ...
553
  	ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
  	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()
  "));
  	sb->s_root = d_alloc_root(root_i);
  	if (!sb->s_root)
  		goto out_root_i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  	sb->s_maxbytes = 0xFFFFFFFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
565
566
567
568
  	sb->s_blocksize = PAGE_CACHE_SIZE;
  	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  	sb->s_magic = JFFS2_SUPER_MAGIC;
  	if (!(sb->s_flags & MS_RDONLY))
  		jffs2_start_garbage_collect_thread(c);
  	return 0;
  
   out_root_i:
  	iput(root_i);
5451f79f5   David Howells   iget: stop JFFS2 ...
569
  out_root:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  	jffs2_free_ino_caches(c);
  	jffs2_free_raw_node_refs(c);
4ce1f5621   Ferenc Havasi   [JFFS2] Remove su...
572
  	if (jffs2_blocks_use_vmalloc(c))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
  		vfree(c->blocks);
  	else
  		kfree(c->blocks);
   out_inohash:
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
577
  	jffs2_clear_xattr_subsystem(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  	kfree(c->inocache_list);
   out_wbuf:
  	jffs2_flash_cleanup(c);
  
  	return ret;
  }
  
  void jffs2_gc_release_inode(struct jffs2_sb_info *c,
  				   struct jffs2_inode_info *f)
  {
  	iput(OFNI_EDONI_2SFFJ(f));
  }
  
  struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
1b690b487   David Woodhouse   [JFFS2] Invert la...
592
  					      int inum, int unlinked)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  {
  	struct inode *inode;
  	struct jffs2_inode_cache *ic;
1b690b487   David Woodhouse   [JFFS2] Invert la...
596
597
  
  	if (unlinked) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  		/* The inode has zero nlink but its nodes weren't yet marked
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
599
  		   obsolete. This has to be because we're still waiting for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  		   the final (close() and) iput() to happen.
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
601
  		   There's a possibility that the final iput() could have
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
  		   happened while we were contemplating. In order to ensure
  		   that we don't cause a new read_inode() (which would fail)
  		   for the inode in question, we use ilookup() in this case
  		   instead of iget().
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
606
  		   The nlink can't _become_ zero at this point because we're
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  		   holding the alloc_sem, and jffs2_do_unlink() would also
  		   need that while decrementing nlink on any inode.
  		*/
  		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
  		if (!inode) {
  			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.
  ",
  				  inum));
  
  			spin_lock(&c->inocache_lock);
  			ic = jffs2_get_ino_cache(c, inum);
  			if (!ic) {
  				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.
  ", inum));
  				spin_unlock(&c->inocache_lock);
  				return NULL;
  			}
  			if (ic->state != INO_STATE_CHECKEDABSENT) {
  				/* Wait for progress. Don't just loop */
  				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d
  ",
  					  ic->ino, ic->state));
  				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
  			} else {
  				spin_unlock(&c->inocache_lock);
  			}
  
  			return NULL;
  		}
  	} else {
  		/* Inode has links to it still; they're not going away because
  		   jffs2_do_unlink() would need the alloc_sem and we have it.
  		   Just iget() it, and if read_inode() is necessary that's OK.
  		*/
5451f79f5   David Howells   iget: stop JFFS2 ...
641
642
643
  		inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
  		if (IS_ERR(inode))
  			return ERR_CAST(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  	}
  	if (is_bad_inode(inode)) {
1b690b487   David Woodhouse   [JFFS2] Invert la...
646
647
648
  		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d
  ",
  		       inum, unlinked);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
  		/* NB. This will happen again. We need to do something appropriate here. */
  		iput(inode);
  		return ERR_PTR(-EIO);
  	}
  
  	return JFFS2_INODE_INFO(inode);
  }
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
656
657
  unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
  				   struct jffs2_inode_info *f,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
661
662
  				   unsigned long offset,
  				   unsigned long *priv)
  {
  	struct inode *inode = OFNI_EDONI_2SFFJ(f);
  	struct page *pg;
fc0e01974   Jason Lunz   [JFFS2] fix write...
663
  	pg = read_cache_page_async(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  			     (void *)jffs2_do_readpage_unlock, inode);
  	if (IS_ERR(pg))
  		return (void *)pg;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
667

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  	*priv = (unsigned long)pg;
  	return kmap(pg);
  }
  
  void jffs2_gc_release_page(struct jffs2_sb_info *c,
  			   unsigned char *ptr,
  			   unsigned long *priv)
  {
  	struct page *pg = (void *)*priv;
  
  	kunmap(pg);
  	page_cache_release(pg);
  }
  
  static int jffs2_flash_setup(struct jffs2_sb_info *c) {
  	int ret = 0;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
684

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
  	if (jffs2_cleanmarker_oob(c)) {
  		/* NAND flash... do setup accordingly */
  		ret = jffs2_nand_flash_setup(c);
  		if (ret)
  			return ret;
  	}
8f15fd55f   Andrew Victor   [JFFS2] Add suppo...
691
692
693
694
695
696
  	/* and Dataflash */
  	if (jffs2_dataflash(c)) {
  		ret = jffs2_dataflash_setup(c);
  		if (ret)
  			return ret;
  	}
59da721a2   Nicolas Pitre   [JFFS2] Teach JFF...
697
698
699
700
701
702
703
  
  	/* and Intel "Sibley" flash */
  	if (jffs2_nor_wbuf_flash(c)) {
  		ret = jffs2_nor_wbuf_flash_setup(c);
  		if (ret)
  			return ret;
  	}
0029da3bf   Artem Bityutskiy   JFFS2: add UBI su...
704
705
706
707
708
709
  	/* and an UBI volume */
  	if (jffs2_ubivol(c)) {
  		ret = jffs2_ubivol_setup(c);
  		if (ret)
  			return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
715
716
717
  	return ret;
  }
  
  void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
  
  	if (jffs2_cleanmarker_oob(c)) {
  		jffs2_nand_flash_cleanup(c);
  	}
8f15fd55f   Andrew Victor   [JFFS2] Add suppo...
718
719
720
721
  	/* and DataFlash */
  	if (jffs2_dataflash(c)) {
  		jffs2_dataflash_cleanup(c);
  	}
59da721a2   Nicolas Pitre   [JFFS2] Teach JFF...
722
723
724
725
726
  
  	/* and Intel "Sibley" flash */
  	if (jffs2_nor_wbuf_flash(c)) {
  		jffs2_nor_wbuf_flash_cleanup(c);
  	}
0029da3bf   Artem Bityutskiy   JFFS2: add UBI su...
727
728
729
730
731
  
  	/* and an UBI volume */
  	if (jffs2_ubivol(c)) {
  		jffs2_ubivol_cleanup(c);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  }