Blame view

fs/jffs2/dir.c 22.9 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
12
13
14
   */
  
  #include <linux/kernel.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
  #include <linux/fs.h>
  #include <linux/crc32.h>
  #include <linux/jffs2.h>
cbb9a5617   David Woodhouse   Move jffs2_fs_i.h...
18
19
  #include "jffs2_fs_i.h"
  #include "jffs2_fs_sb.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/time.h>
  #include "nodelist.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
  static int jffs2_readdir (struct file *, void *, filldir_t);
  
  static int jffs2_create (struct inode *,struct dentry *,int,
  			 struct nameidata *);
  static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
  				    struct nameidata *);
  static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
  static int jffs2_unlink (struct inode *,struct dentry *);
  static int jffs2_symlink (struct inode *,struct dentry *,const char *);
  static int jffs2_mkdir (struct inode *,struct dentry *,int);
  static int jffs2_rmdir (struct inode *,struct dentry *);
265489f01   David Woodhouse   [JFFS2] Remove co...
33
  static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  static int jffs2_rename (struct inode *, struct dentry *,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
35
  			 struct inode *, struct dentry *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
37
  const struct file_operations jffs2_dir_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  {
  	.read =		generic_read_dir,
  	.readdir =	jffs2_readdir,
0533400b7   Stoyan Gaydarov   [JFFS2] Use .unlo...
41
  	.unlocked_ioctl=jffs2_ioctl,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
42
43
  	.fsync =	jffs2_fsync,
  	.llseek =	generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
45
  const struct inode_operations jffs2_dir_inode_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  {
265489f01   David Woodhouse   [JFFS2] Remove co...
47
48
  	.create =	jffs2_create,
  	.lookup =	jffs2_lookup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
  	.link =		jffs2_link,
  	.unlink =	jffs2_unlink,
  	.symlink =	jffs2_symlink,
  	.mkdir =	jffs2_mkdir,
  	.rmdir =	jffs2_rmdir,
  	.mknod =	jffs2_mknod,
  	.rename =	jffs2_rename,
4e34e719e   Christoph Hellwig   fs: take the ACL ...
56
  	.get_acl =	jffs2_get_acl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  	.setattr =	jffs2_setattr,
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
58
59
60
61
  	.setxattr =	jffs2_setxattr,
  	.getxattr =	jffs2_getxattr,
  	.listxattr =	jffs2_listxattr,
  	.removexattr =	jffs2_removexattr
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
  };
  
  /***********************************************************************/
  
  
  /* We keep the dirent list sorted in increasing order of name hash,
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
68
     and we use the same hash function as the dentries. Makes this
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
     nice and simple
  */
  static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
  				   struct nameidata *nd)
  {
  	struct jffs2_inode_info *dir_f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
  	struct jffs2_full_dirent *fd = NULL, *fd_list;
  	uint32_t ino = 0;
  	struct inode *inode = NULL;
  
  	D1(printk(KERN_DEBUG "jffs2_lookup()
  "));
373d5e718   Richard Purdie   JFFS2: Return an ...
81
82
  	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
  		return ERR_PTR(-ENAMETOOLONG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  	dir_f = JFFS2_INODE_INFO(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

ced220703   David Woodhouse   [JFFS2] semaphore...
85
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  
  	/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
  	for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
89
  		if (fd_list->nhash == target->d_name.hash &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
  		    (!fd || fd_list->version > fd->version) &&
  		    strlen(fd_list->name) == target->d_name.len &&
  		    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
  			fd = fd_list;
  		}
  	}
  	if (fd)
  		ino = fd->ino;
ced220703   David Woodhouse   [JFFS2] semaphore...
98
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  	if (ino) {
5451f79f5   David Howells   iget: stop JFFS2 ...
100
  		inode = jffs2_iget(dir_i->i_sb, ino);
a9049376e   Al Viro   make d_splice_ali...
101
  		if (IS_ERR(inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  			printk(KERN_WARNING "iget() failed for ino #%u
  ", ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	}
8966c5e0f   David Woodhouse   [JFFS2] Use d_spl...
105
  	return d_splice_alias(inode, target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
113
  }
  
  /***********************************************************************/
  
  
  static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
  	struct jffs2_inode_info *f;
ec2e203c8   Josef Sipek   [PATCH] struct pa...
114
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  	struct jffs2_full_dirent *fd;
  	unsigned long offset, curofs;
ec2e203c8   Josef Sipek   [PATCH] struct pa...
117
118
  	D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu
  ", filp->f_path.dentry->d_inode->i_ino));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  
  	f = JFFS2_INODE_INFO(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
  
  	offset = filp->f_pos;
  
  	if (offset == 0) {
  		D1(printk(KERN_DEBUG "Dirent 0: \".\", ino #%lu
  ", inode->i_ino));
  		if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
  			goto out;
  		offset++;
  	}
  	if (offset == 1) {
ec2e203c8   Josef Sipek   [PATCH] struct pa...
132
  		unsigned long pino = parent_ino(filp->f_path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
  		D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu
  ", pino));
  		if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
  			goto out;
  		offset++;
  	}
  
  	curofs=1;
ced220703   David Woodhouse   [JFFS2] semaphore...
141
  	mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
  	for (fd = f->dents; fd; fd = fd->next) {
  
  		curofs++;
  		/* First loop: curofs = 2; offset = 2 */
  		if (curofs < offset) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
147
148
  			D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  				  fd->name, fd->ino, fd->type, curofs, offset));
  			continue;
  		}
  		if (!fd->ino) {
  			D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"
  ", fd->name));
  			offset++;
  			continue;
  		}
  		D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d
  ", offset, fd->name, fd->ino, fd->type));
  		if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
  			break;
  		offset++;
  	}
ced220703   David Woodhouse   [JFFS2] semaphore...
164
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
   out:
  	filp->f_pos = offset;
  	return 0;
  }
  
  /***********************************************************************/
  
  
  static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
  			struct nameidata *nd)
  {
  	struct jffs2_raw_inode *ri;
  	struct jffs2_inode_info *f, *dir_f;
  	struct jffs2_sb_info *c;
  	struct inode *inode;
  	int ret;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
185

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
  	c = JFFS2_SB_INFO(dir_i->i_sb);
  
  	D1(printk(KERN_DEBUG "jffs2_create()
  "));
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
190
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  
  	if (IS_ERR(inode)) {
  		D1(printk(KERN_DEBUG "jffs2_new_inode() failed
  "));
  		jffs2_free_raw_inode(ri);
  		return PTR_ERR(inode);
  	}
  
  	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;
  
  	f = JFFS2_INODE_INFO(inode);
  	dir_f = JFFS2_INODE_INFO(dir_i);
590fe34c4   David Woodhouse   [JFFS2] Quiet loc...
206
207
208
209
210
211
  	/* jffs2_do_create() will want to lock it, _after_ reserving
  	   space and taking c-alloc_sem. If we keep it locked here,
  	   lockdep gets unhappy (although it's a false positive;
  	   nothing else will be looking at this inode yet so there's
  	   no chance of AB-BA deadlock involving its f->sem). */
  	mutex_unlock(&f->sem);
2a7dba391   Eric Paris   fs/vfs/security: ...
212
  	ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
213
214
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
  
  	jffs2_free_raw_inode(ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
  
  	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld
  ",
27c72b040   David Woodhouse   [JFFS2] Track par...
222
223
  		  inode->i_ino, inode->i_mode, inode->i_nlink,
  		  f->inocache->pino_nlink, inode->i_mapping->nrpages));
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
224
225
226
  
  	d_instantiate(dentry, inode);
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
228
229
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
230
  	iget_failed(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
231
232
  	jffs2_free_raw_inode(ri);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
237
238
239
240
241
242
243
  }
  
  /***********************************************************************/
  
  
  static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
  	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
  	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode);
  	int ret;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
244
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
246
  	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
247
  			      dentry->d_name.len, dead_f, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	if (dead_f->inocache)
bfe868486   Miklos Szeredi   filesystems: add ...
249
  		set_nlink(dentry->d_inode, dead_f->inocache->pino_nlink);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
250
251
  	if (!ret)
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
261
262
263
  	return ret;
  }
  /***********************************************************************/
  
  
  static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb);
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
  	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
  	int ret;
  	uint8_t type;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
264
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
274
275
  
  	/* Don't let people make hard links to bad inodes. */
  	if (!f->inocache)
  		return -EIO;
  
  	if (S_ISDIR(old_dentry->d_inode->i_mode))
  		return -EPERM;
  
  	/* XXX: This is ugly */
  	type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
  	if (!type) type = DT_REG;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
276
277
  	now = get_seconds();
  	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
  
  	if (!ret) {
ced220703   David Woodhouse   [JFFS2] semaphore...
280
  		mutex_lock(&f->sem);
bfe868486   Miklos Szeredi   filesystems: add ...
281
  		set_nlink(old_dentry->d_inode, ++f->inocache->pino_nlink);
ced220703   David Woodhouse   [JFFS2] semaphore...
282
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  		d_instantiate(dentry, old_dentry->d_inode);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
284
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
7de9c6ee3   Al Viro   new helper: ihold()
285
  		ihold(old_dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  	}
  	return ret;
  }
  
  /***********************************************************************/
  
  static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target)
  {
  	struct jffs2_inode_info *f, *dir_f;
  	struct jffs2_sb_info *c;
  	struct inode *inode;
  	struct jffs2_raw_inode *ri;
  	struct jffs2_raw_dirent *rd;
  	struct jffs2_full_dnode *fn;
  	struct jffs2_full_dirent *fd;
  	int namelen;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
302
  	uint32_t alloclen;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
303
  	int ret, targetlen = strlen(target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
  
  	/* FIXME: If you care. We'd need to use frags for the target
  	   if it grows much more than this */
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
307
  	if (targetlen > 254)
bde86fec7   Adrian Hunter   [JFFS2] Correct s...
308
  		return -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
  
  	ri = jffs2_alloc_raw_inode();
  
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
314

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
316
317
318
  
  	/* Try to reserve enough space for both node and dirent.
  	 * Just the node will do for now, though
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
321
322
  	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
328
  	inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
334
335
336
337
338
  
  	if (IS_ERR(inode)) {
  		jffs2_free_raw_inode(ri);
  		jffs2_complete_reservation(c);
  		return PTR_ERR(inode);
  	}
  
  	inode->i_op = &jffs2_symlink_inode_operations;
  
  	f = JFFS2_INODE_INFO(inode);
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
339
  	inode->i_size = targetlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
  	ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
  	ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
  	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
  
  	ri->compr = JFFS2_COMPR_NONE;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
345
  	ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
347

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
348
  	fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
354
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
356
357
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	}
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
359

2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
360
  	/* We use f->target field to store the target path. */
04aadf36d   Julia Lawall   jffs2: use kmemdup
361
  	f->target = kmemdup(target, targetlen + 1, GFP_KERNEL);
2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
362
  	if (!f->target) {
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
363
364
  		printk(KERN_WARNING "Can't allocate %d bytes of memory
  ", targetlen + 1);
ced220703   David Woodhouse   [JFFS2] semaphore...
365
  		mutex_unlock(&f->sem);
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
366
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
367
368
  		ret = -ENOMEM;
  		goto fail;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
369
  	}
2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
370
371
  	D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached
  ", (char *)f->target));
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
372

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
373
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
377
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
380

2a7dba391   Eric Paris   fs/vfs/security: ...
381
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
382
383
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
384
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
385
386
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
387

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
388
389
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
390
391
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
  
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
397
398
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
402
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  
  	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
  	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
  	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
  
  	rd->pino = cpu_to_je32(dir_i->i_ino);
  	rd->version = cpu_to_je32(++dir_f->highest_version);
  	rd->ino = cpu_to_je32(inode->i_ino);
  	rd->mctime = cpu_to_je32(get_seconds());
  	rd->nsize = namelen;
  	rd->type = DT_LNK;
  	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
  	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
417
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
420
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
424
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
425
426
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
430
431
432
433
434
435
  	}
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
  
  	jffs2_free_raw_dirent(rd);
  
  	/* Link the fd into the inode's list, obsoleting an old
  	   one if necessary. */
  	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
ced220703   David Woodhouse   [JFFS2] semaphore...
436
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
440
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
442
443
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
444
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
445
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
452
453
454
455
456
457
458
  }
  
  
  static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
  {
  	struct jffs2_inode_info *f, *dir_f;
  	struct jffs2_sb_info *c;
  	struct inode *inode;
  	struct jffs2_raw_inode *ri;
  	struct jffs2_raw_dirent *rd;
  	struct jffs2_full_dnode *fn;
  	struct jffs2_full_dirent *fd;
  	int namelen;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
459
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
465
466
  	int ret;
  
  	mode |= S_IFDIR;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
467

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
469
470
  	/* Try to reserve enough space for both node and dirent.
  	 * Just the node will do for now, though
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
473
474
  	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
  				  JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
480
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
487
488
489
  
  	if (IS_ERR(inode)) {
  		jffs2_free_raw_inode(ri);
  		jffs2_complete_reservation(c);
  		return PTR_ERR(inode);
  	}
  
  	inode->i_op = &jffs2_dir_inode_operations;
  	inode->i_fop = &jffs2_dir_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  
  	f = JFFS2_INODE_INFO(inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
492
  	/* Directories get nlink 2 at start */
bfe868486   Miklos Szeredi   filesystems: add ...
493
  	set_nlink(inode, 2);
27c72b040   David Woodhouse   [JFFS2] Track par...
494
495
  	/* but ic->pino_nlink is the parent ino# */
  	f->inocache->pino_nlink = dir_i->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  	ri->data_crc = cpu_to_je32(0);
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
498

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
499
  	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
503
504
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
505
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
507
508
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
510
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
514
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
517

2a7dba391   Eric Paris   fs/vfs/security: ...
518
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
519
520
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
521
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
522
523
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
524

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
525
526
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
527
528
  	if (ret)
  		goto fail;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
529

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
534
535
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
539
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  
  	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
  	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
  	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
  
  	rd->pino = cpu_to_je32(dir_i->i_ino);
  	rd->version = cpu_to_je32(++dir_f->highest_version);
  	rd->ino = cpu_to_je32(inode->i_ino);
  	rd->mctime = cpu_to_je32(get_seconds());
  	rd->nsize = namelen;
  	rd->type = DT_DIR;
  	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
  	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
554
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
555

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
557
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
561
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
562
563
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
  	}
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
567
  	inc_nlink(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
572
573
  
  	jffs2_free_raw_dirent(rd);
  
  	/* Link the fd into the inode's list, obsoleting an old
  	   one if necessary. */
  	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
ced220703   David Woodhouse   [JFFS2] semaphore...
574
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
578
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
580
581
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
582
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
583
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
  }
  
  static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
  {
27c72b040   David Woodhouse   [JFFS2] Track par...
588
589
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
  	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
  	struct jffs2_full_dirent *fd;
  	int ret;
27c72b040   David Woodhouse   [JFFS2] Track par...
593
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
  
  	for (fd = f->dents ; fd; fd = fd->next) {
  		if (fd->ino)
  			return -ENOTEMPTY;
  	}
27c72b040   David Woodhouse   [JFFS2] Track par...
599
600
601
602
603
604
  
  	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
  			      dentry->d_name.len, f, now);
  	if (!ret) {
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
  		clear_nlink(dentry->d_inode);
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
605
  		drop_nlink(dir_i);
27c72b040   David Woodhouse   [JFFS2] Track par...
606
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
  	return ret;
  }
265489f01   David Woodhouse   [JFFS2] Remove co...
609
  static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
614
615
616
617
618
  {
  	struct jffs2_inode_info *f, *dir_f;
  	struct jffs2_sb_info *c;
  	struct inode *inode;
  	struct jffs2_raw_inode *ri;
  	struct jffs2_raw_dirent *rd;
  	struct jffs2_full_dnode *fn;
  	struct jffs2_full_dirent *fd;
  	int namelen;
aef9ab478   David Woodhouse   [JFFS2] Support n...
619
  	union jffs2_device_node dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  	int devlen = 0;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
621
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  	int ret;
aef9ab478   David Woodhouse   [JFFS2] Support n...
623
  	if (!new_valid_dev(rdev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
  		return -EINVAL;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
629

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
631

aef9ab478   David Woodhouse   [JFFS2] Support n...
632
633
  	if (S_ISBLK(mode) || S_ISCHR(mode))
  		devlen = jffs2_encode_dev(&dev, rdev);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
634
635
636
  
  	/* Try to reserve enough space for both node and dirent.
  	 * Just the node will do for now, though
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
639
  	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
aef9ab478   David Woodhouse   [JFFS2] Support n...
640
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
646
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  
  	if (IS_ERR(inode)) {
  		jffs2_free_raw_inode(ri);
  		jffs2_complete_reservation(c);
  		return PTR_ERR(inode);
  	}
  	inode->i_op = &jffs2_file_inode_operations;
  	init_special_inode(inode, inode->i_mode, rdev);
  
  	f = JFFS2_INODE_INFO(inode);
  
  	ri->dsize = ri->csize = cpu_to_je32(devlen);
  	ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
  	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
  
  	ri->compr = JFFS2_COMPR_NONE;
  	ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
665

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
666
  	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
672
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
674
675
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
677
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
681
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
684

2a7dba391   Eric Paris   fs/vfs/security: ...
685
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
686
687
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
688
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
689
690
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
691

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
692
693
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
694
695
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
  
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
701
702
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
706
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
  
  	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
  	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
  	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
  
  	rd->pino = cpu_to_je32(dir_i->i_ino);
  	rd->version = cpu_to_je32(++dir_f->highest_version);
  	rd->ino = cpu_to_je32(inode->i_ino);
  	rd->mctime = cpu_to_je32(get_seconds());
  	rd->nsize = namelen;
  
  	/* XXX: This is ugly. */
  	rd->type = (mode & S_IFMT) >> 12;
  
  	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
  	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
724
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
725

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
727
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
731
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
732
733
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
739
740
741
742
  	}
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
  
  	jffs2_free_raw_dirent(rd);
  
  	/* Link the fd into the inode's list, obsoleting an old
  	   one if necessary. */
  	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
ced220703   David Woodhouse   [JFFS2] semaphore...
743
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
747
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
749
750
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
751
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
752
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
  }
  
  static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
756
  			 struct inode *new_dir_i, struct dentry *new_dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
  {
  	int ret;
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
  	struct jffs2_inode_info *victim_f = NULL;
  	uint8_t type;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
762
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
764
  	/* The VFS will check for us and prevent trying to rename a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
771
772
  	 * file over a directory and vice versa, but if it's a directory,
  	 * the VFS can't check whether the victim is empty. The filesystem
  	 * needs to do that for itself.
  	 */
  	if (new_dentry->d_inode) {
  		victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
  		if (S_ISDIR(new_dentry->d_inode->i_mode)) {
  			struct jffs2_full_dirent *fd;
ced220703   David Woodhouse   [JFFS2] semaphore...
773
  			mutex_lock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
  			for (fd = victim_f->dents; fd; fd = fd->next) {
  				if (fd->ino) {
ced220703   David Woodhouse   [JFFS2] semaphore...
776
  					mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
  					return -ENOTEMPTY;
  				}
  			}
ced220703   David Woodhouse   [JFFS2] semaphore...
780
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
  		}
  	}
  
  	/* XXX: We probably ought to alloc enough space for
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
785
  	   both nodes at the same time. Writing the new link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
  	   then getting -ENOSPC, is quite bad :)
  	*/
  
  	/* Make a hard link */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
790

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
  	/* XXX: This is ugly */
  	type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
  	if (!type) type = DT_REG;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
794
  	now = get_seconds();
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
795
  	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  			    old_dentry->d_inode->i_ino, type,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
797
  			    new_dentry->d_name.name, new_dentry->d_name.len, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
801
802
803
  
  	if (ret)
  		return ret;
  
  	if (victim_f) {
  		/* There was a victim. Kill it off nicely */
22ba747f6   Al Viro   jffs2: fix IN_DEL...
804
805
806
807
  		if (S_ISDIR(new_dentry->d_inode->i_mode))
  			clear_nlink(new_dentry->d_inode);
  		else
  			drop_nlink(new_dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
  		/* Don't oops if the victim was a dirent pointing to an
  		   inode which didn't exist. */
  		if (victim_f->inocache) {
ced220703   David Woodhouse   [JFFS2] semaphore...
811
  			mutex_lock(&victim_f->sem);
27c72b040   David Woodhouse   [JFFS2] Track par...
812
813
814
815
  			if (S_ISDIR(new_dentry->d_inode->i_mode))
  				victim_f->inocache->pino_nlink = 0;
  			else
  				victim_f->inocache->pino_nlink--;
ced220703   David Woodhouse   [JFFS2] semaphore...
816
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
  		}
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
819
  	/* If it was a directory we moved, and there was no victim,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
  	   increase i_nlink on its new parent */
  	if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
822
  		inc_nlink(new_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
  
  	/* Unlink the original */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
825
  	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
826
  			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
  
  	/* We don't touch inode->i_nlink */
  
  	if (ret) {
  		/* Oh shit. We really ought to make a single node which can do both atomically */
  		struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
ced220703   David Woodhouse   [JFFS2] semaphore...
833
  		mutex_lock(&f->sem);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
834
  		inc_nlink(old_dentry->d_inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
835
836
  		if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
  			f->inocache->pino_nlink++;
ced220703   David Woodhouse   [JFFS2] semaphore...
837
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
841
842
  
  		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link
  ", ret);
  		/* Might as well let the VFS know */
  		d_instantiate(new_dentry, old_dentry->d_inode);
7de9c6ee3   Al Viro   new helper: ihold()
843
  		ihold(old_dentry->d_inode);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
844
  		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
  		return ret;
  	}
  
  	if (S_ISDIR(old_dentry->d_inode->i_mode))
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
849
  		drop_nlink(old_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850

3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
851
  	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  	return 0;
  }