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
  static int jffs2_readdir (struct file *, void *, filldir_t);
4acdaf27e   Al Viro   switch ->create()...
23
  static int jffs2_create (struct inode *,struct dentry *,umode_t,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
  			 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 *);
18bb1db3e   Al Viro   switch vfs_mkdir(...
30
  static int jffs2_mkdir (struct inode *,struct dentry *,umode_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  static int jffs2_rmdir (struct inode *,struct dentry *);
1a67aafb5   Al Viro   switch ->mknod() ...
32
  static int jffs2_mknod (struct inode *,struct dentry *,umode_t,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,
4e34e719e   Christoph Hellwig   fs: take the ACL ...
55
  	.get_acl =	jffs2_get_acl,
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
     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
74
75
76
77
78
79
  	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 ...
80
81
  	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
  		return ERR_PTR(-ENAMETOOLONG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  	dir_f = JFFS2_INODE_INFO(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
  	c = JFFS2_SB_INFO(dir_i->i_sb);
  
  	D1(printk(KERN_DEBUG "jffs2_create()
  "));
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
187
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  
  	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...
203
204
205
206
207
208
  	/* 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: ...
209
  	ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
210
211
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
  
  	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
216
217
218
  
  	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld
  ",
27c72b040   David Woodhouse   [JFFS2] Track par...
219
220
  		  inode->i_ino, inode->i_mode, inode->i_nlink,
  		  f->inocache->pino_nlink, inode->i_mapping->nrpages));
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
221
222
223
  
  	d_instantiate(dentry, inode);
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
225
226
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
227
  	iget_failed(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
228
229
  	jffs2_free_raw_inode(ri);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
240
  }
  
  /***********************************************************************/
  
  
  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...
241
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242

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

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

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

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

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

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

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
385
386
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
387
388
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
  
  	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...
394
395
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
399
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  
  	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...
414
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
  
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
417
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
421
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
422
423
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
428
429
430
431
432
  	}
  
  	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...
433
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
437
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
439
440
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
441
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
442
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
444
  static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
453
  {
  	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...
454
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
  	int ret;
  
  	mode |= S_IFDIR;
  
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
462

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
464
465
  	/* 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
466
467
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
468
469
  	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
  				  JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
475
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
481
482
483
484
  
  	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
485
486
  
  	f = JFFS2_INODE_INFO(inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
487
  	/* Directories get nlink 2 at start */
bfe868486   Miklos Szeredi   filesystems: add ...
488
  	set_nlink(inode, 2);
27c72b040   David Woodhouse   [JFFS2] Track par...
489
490
  	/* but ic->pino_nlink is the parent ino# */
  	f->inocache->pino_nlink = dir_i->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  	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 ...
493

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
  	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...
529
530
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
534
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  
  	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...
549
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
550

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

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

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

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

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

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
687
688
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
689
690
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
694
695
  
  	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...
696
697
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
701
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  
  	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...
719
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
720

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
722
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
726
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
727
728
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
731
732
733
734
735
736
737
  	}
  
  	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...
738
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
  	jffs2_complete_reservation(c);
  
  	d_instantiate(dentry, inode);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
742
  	unlock_new_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
744
745
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
746
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
747
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
  }
  
  static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
751
  			 struct inode *new_dir_i, struct dentry *new_dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
  {
  	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...
757
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
759
  	/* The VFS will check for us and prevent trying to rename a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
762
763
764
765
766
767
  	 * 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...
768
  			mutex_lock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  			for (fd = victim_f->dents; fd; fd = fd->next) {
  				if (fd->ino) {
ced220703   David Woodhouse   [JFFS2] semaphore...
771
  					mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
  					return -ENOTEMPTY;
  				}
  			}
ced220703   David Woodhouse   [JFFS2] semaphore...
775
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
  		}
  	}
  
  	/* XXX: We probably ought to alloc enough space for
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
780
  	   both nodes at the same time. Writing the new link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
  	   then getting -ENOSPC, is quite bad :)
  	*/
  
  	/* Make a hard link */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
785

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

3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
846
  	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
847
848
  	return 0;
  }