Blame view

fs/jffs2/dir.c 23.2 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
   *
   * 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
10
11
12
13
   */
  
  #include <linux/kernel.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
  #include <linux/fs.h>
  #include <linux/crc32.h>
  #include <linux/jffs2.h>
cbb9a5617   David Woodhouse   Move jffs2_fs_i.h...
17
18
  #include "jffs2_fs_i.h"
  #include "jffs2_fs_sb.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/time.h>
  #include "nodelist.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
31
  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...
32
  static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  static int jffs2_rename (struct inode *, struct dentry *,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
34
  			 struct inode *, struct dentry *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
36
  const struct file_operations jffs2_dir_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  {
  	.read =		generic_read_dir,
  	.readdir =	jffs2_readdir,
0533400b7   Stoyan Gaydarov   [JFFS2] Use .unlo...
40
  	.unlocked_ioctl=jffs2_ioctl,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
41
42
  	.fsync =	jffs2_fsync,
  	.llseek =	generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
44
  const struct inode_operations jffs2_dir_inode_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  {
265489f01   David Woodhouse   [JFFS2] Remove co...
46
47
  	.create =	jffs2_create,
  	.lookup =	jffs2_lookup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
  	.link =		jffs2_link,
  	.unlink =	jffs2_unlink,
  	.symlink =	jffs2_symlink,
  	.mkdir =	jffs2_mkdir,
  	.rmdir =	jffs2_rmdir,
  	.mknod =	jffs2_mknod,
  	.rename =	jffs2_rename,
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
55
  	.permission =	jffs2_permission,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  	.setattr =	jffs2_setattr,
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
57
58
59
60
  	.setxattr =	jffs2_setxattr,
  	.getxattr =	jffs2_getxattr,
  	.listxattr =	jffs2_listxattr,
  	.removexattr =	jffs2_removexattr
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
  };
  
  /***********************************************************************/
  
  
  /* We keep the dirent list sorted in increasing order of name hash,
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
67
     and we use the same hash function as the dentries. Makes this
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
     nice and simple
  */
  static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
  				   struct nameidata *nd)
  {
  	struct jffs2_inode_info *dir_f;
  	struct jffs2_sb_info *c;
  	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
84
  	dir_f = JFFS2_INODE_INFO(dir_i);
  	c = JFFS2_SB_INFO(dir_i->i_sb);
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
101
  		inode = jffs2_iget(dir_i->i_sb, ino);
  		if (IS_ERR(inode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  			printk(KERN_WARNING "iget() failed for ino #%u
  ", ino);
5451f79f5   David Howells   iget: stop JFFS2 ...
104
  			return ERR_CAST(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  		}
  	}
8966c5e0f   David Woodhouse   [JFFS2] Use d_spl...
107
  	return d_splice_alias(inode, target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
  }
  
  /***********************************************************************/
  
  
  static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
  	struct jffs2_inode_info *f;
  	struct jffs2_sb_info *c;
ec2e203c8   Josef Sipek   [PATCH] struct pa...
117
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  	struct jffs2_full_dirent *fd;
  	unsigned long offset, curofs;
ec2e203c8   Josef Sipek   [PATCH] struct pa...
120
121
  	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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  
  	f = JFFS2_INODE_INFO(inode);
  	c = JFFS2_SB_INFO(inode->i_sb);
  
  	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...
136
  		unsigned long pino = parent_ino(filp->f_path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
  		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...
145
  	mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
  	for (fd = f->dents; fd; fd = fd->next) {
  
  		curofs++;
  		/* First loop: curofs = 2; offset = 2 */
  		if (curofs < offset) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
151
152
  			D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  				  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...
168
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
   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 ...
189

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
  	c = JFFS2_SB_INFO(dir_i->i_sb);
  
  	D1(printk(KERN_DEBUG "jffs2_create()
  "));
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
194
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  
  	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...
210
211
212
213
214
215
  	/* 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);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
216
  	ret = jffs2_do_create(c, dir_f, f, ri,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  			      dentry->d_name.name, dentry->d_name.len);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
218
219
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
227
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
  
  	jffs2_free_raw_inode(ri);
  	d_instantiate(dentry, inode);
  
  	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld
  ",
27c72b040   David Woodhouse   [JFFS2] Track par...
228
229
  		  inode->i_ino, inode->i_mode, inode->i_nlink,
  		  f->inocache->pino_nlink, inode->i_mapping->nrpages));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
231
232
233
234
235
236
  
   fail:
  	make_bad_inode(inode);
  	iput(inode);
  	jffs2_free_raw_inode(ri);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
  }
  
  /***********************************************************************/
  
  
  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...
248
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
250
  	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
251
  			      dentry->d_name.len, dead_f, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	if (dead_f->inocache)
27c72b040   David Woodhouse   [JFFS2] Track par...
253
  		dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
254
255
  	if (!ret)
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
  	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...
268
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
274
275
276
277
278
279
  
  	/* 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...
280
281
  	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
282
283
  
  	if (!ret) {
ced220703   David Woodhouse   [JFFS2] semaphore...
284
  		mutex_lock(&f->sem);
27c72b040   David Woodhouse   [JFFS2] Track par...
285
  		old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
ced220703   David Woodhouse   [JFFS2] semaphore...
286
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  		d_instantiate(dentry, old_dentry->d_inode);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
288
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  		atomic_inc(&old_dentry->d_inode->i_count);
  	}
  	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...
306
  	uint32_t alloclen;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
307
  	int ret, targetlen = strlen(target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
  
  	/* 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...
311
  	if (targetlen > 254)
bde86fec7   Adrian Hunter   [JFFS2] Correct s...
312
  		return -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
  
  	ri = jffs2_alloc_raw_inode();
  
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
318

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
320
321
322
  
  	/* 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
323
324
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
325
326
  	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
332
  	inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
339
340
341
342
  
  	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...
343
  	inode->i_size = targetlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  	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...
349
  	ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
351

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
352
  	fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
358
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fn);
  	}
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
363

2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
364
365
366
  	/* We use f->target field to store the target path. */
  	f->target = kmalloc(targetlen + 1, GFP_KERNEL);
  	if (!f->target) {
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
367
368
  		printk(KERN_WARNING "Can't allocate %d bytes of memory
  ", targetlen + 1);
ced220703   David Woodhouse   [JFFS2] semaphore...
369
  		mutex_unlock(&f->sem);
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
370
371
372
373
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return -ENOMEM;
  	}
2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
374
375
376
  	memcpy(f->target, target, targetlen + 1);
  	D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached
  ", (char *)f->target));
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
377

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
378
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
382
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
385
386
387
388
389
390
  
  	ret = jffs2_init_security(inode, dir_i);
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
391
  	ret = jffs2_init_acl_post(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
392
393
394
395
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
396
397
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	if (ret) {
  		/* Eep. */
  		jffs2_clear_inode(inode);
  		return ret;
  	}
  
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return -ENOMEM;
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
413
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  
  	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...
428
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
431
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
435
  		mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
441
442
443
444
445
446
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fd);
  	}
  
  	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...
447
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
  	return 0;
  }
  
  
  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...
465
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
472
  	int ret;
  
  	mode |= S_IFDIR;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
473

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
475
476
  	/* 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
477
478
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
479
480
  	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
  				  JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
486
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
  
  	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
496
497
  
  	f = JFFS2_INODE_INFO(inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
498
499
500
501
  	/* Directories get nlink 2 at start */
  	inode->i_nlink = 2;
  	/* but ic->pino_nlink is the parent ino# */
  	f->inocache->pino_nlink = dir_i->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
  	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 ...
504

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
505
  	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
511
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fn);
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
516
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
520
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
523
524
525
526
527
528
  
  	ret = jffs2_init_security(inode, dir_i);
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
529
  	ret = jffs2_init_acl_post(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
530
531
532
533
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
534
535
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
  	if (ret) {
  		/* Eep. */
  		jffs2_clear_inode(inode);
  		return ret;
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
541

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
548
549
550
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return -ENOMEM;
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
551
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  
  	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...
566
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
567

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
569
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
573
  		mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fd);
  	}
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
579
  	inc_nlink(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
  
  	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...
586
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
592
593
594
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
  	return 0;
  }
  
  static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
  {
27c72b040   David Woodhouse   [JFFS2] Track par...
595
596
  	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
597
598
599
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
  	struct jffs2_full_dirent *fd;
  	int ret;
27c72b040   David Woodhouse   [JFFS2] Track par...
600
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
  
  	for (fd = f->dents ; fd; fd = fd->next) {
  		if (fd->ino)
  			return -ENOTEMPTY;
  	}
27c72b040   David Woodhouse   [JFFS2] Track par...
606
607
608
609
610
611
  
  	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 ...
612
  		drop_nlink(dir_i);
27c72b040   David Woodhouse   [JFFS2] Track par...
613
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  	return ret;
  }
265489f01   David Woodhouse   [JFFS2] Remove co...
616
  static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
  {
  	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...
626
  	union jffs2_device_node dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
  	int devlen = 0;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
628
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	int ret;
aef9ab478   David Woodhouse   [JFFS2] Support n...
630
  	if (!new_valid_dev(rdev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
  		return -EINVAL;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
636

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

aef9ab478   David Woodhouse   [JFFS2] Support n...
639
640
  	if (S_ISBLK(mode) || S_ISCHR(mode))
  		devlen = jffs2_encode_dev(&dev, rdev);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
641
642
643
  
  	/* 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
644
645
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
646
  	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
aef9ab478   David Woodhouse   [JFFS2] Support n...
647
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
653
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  
  	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 ...
672

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
673
  	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
678
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
679
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fn);
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
684
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
688
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
691
692
693
694
695
696
  
  	ret = jffs2_init_security(inode, dir_i);
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
697
  	ret = jffs2_init_acl_post(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
698
699
700
701
  	if (ret) {
  		jffs2_clear_inode(inode);
  		return ret;
  	}
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
702
703
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  	if (ret) {
  		/* Eep. */
  		jffs2_clear_inode(inode);
  		return ret;
  	}
  
  	rd = jffs2_alloc_raw_dirent();
  	if (!rd) {
  		/* Argh. Now we treat it like a normal delete */
  		jffs2_complete_reservation(c);
  		jffs2_clear_inode(inode);
  		return -ENOMEM;
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
719
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
  
  	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...
737
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
738

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
740
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
744
  		mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
749
750
751
752
753
754
755
  		jffs2_clear_inode(inode);
  		return PTR_ERR(fd);
  	}
  
  	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...
756
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
763
764
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
  
  	return 0;
  }
  
  static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
765
  			 struct inode *new_dir_i, struct dentry *new_dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
  {
  	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...
771
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
773
  	/* The VFS will check for us and prevent trying to rename a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
776
777
778
779
780
781
  	 * 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...
782
  			mutex_lock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  			for (fd = victim_f->dents; fd; fd = fd->next) {
  				if (fd->ino) {
ced220703   David Woodhouse   [JFFS2] semaphore...
785
  					mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
  					return -ENOTEMPTY;
  				}
  			}
ced220703   David Woodhouse   [JFFS2] semaphore...
789
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
793
  		}
  	}
  
  	/* XXX: We probably ought to alloc enough space for
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
794
  	   both nodes at the same time. Writing the new link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
  	   then getting -ENOSPC, is quite bad :)
  	*/
  
  	/* Make a hard link */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
799

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
  	/* 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...
803
  	now = get_seconds();
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
804
  	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  			    old_dentry->d_inode->i_ino, type,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
806
  			    new_dentry->d_name.name, new_dentry->d_name.len, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
812
  
  	if (ret)
  		return ret;
  
  	if (victim_f) {
  		/* There was a victim. Kill it off nicely */
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
813
  		drop_nlink(new_dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
  		/* 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...
817
  			mutex_lock(&victim_f->sem);
27c72b040   David Woodhouse   [JFFS2] Track par...
818
819
820
821
  			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...
822
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
  		}
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
825
  	/* If it was a directory we moved, and there was no victim,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
  	   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 ...
828
  		inc_nlink(new_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
  
  	/* Unlink the original */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
831
  	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
832
  			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
836
837
838
  
  	/* 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...
839
  		mutex_lock(&f->sem);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
840
  		inc_nlink(old_dentry->d_inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
841
842
  		if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
  			f->inocache->pino_nlink++;
ced220703   David Woodhouse   [JFFS2] semaphore...
843
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
847
848
849
  
  		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);
  		atomic_inc(&old_dentry->d_inode->i_count);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
850
  		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
854
  		return ret;
  	}
  
  	if (S_ISDIR(old_dentry->d_inode->i_mode))
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
855
  		drop_nlink(old_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856

3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
857
  	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
858
859
  	return 0;
  }