Blame view

fs/jffs2/dir.c 22.5 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
   */
5a528957e   Joe Perches   jffs2: Use pr_fmt...
12
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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"
0312fa7cc   Al Viro   [readdir] convert...
22
  static int jffs2_readdir (struct file *, struct dir_context *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

4acdaf27e   Al Viro   switch ->create()...
24
  static int jffs2_create (struct inode *,struct dentry *,umode_t,
ebfc3b49a   Al Viro   don't pass nameid...
25
  			 bool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
00cd8dd3b   Al Viro   stop passing name...
27
  				    unsigned int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  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(...
31
  static int jffs2_mkdir (struct inode *,struct dentry *,umode_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  static int jffs2_rmdir (struct inode *,struct dentry *);
1a67aafb5   Al Viro   switch ->mknod() ...
33
  static int jffs2_mknod (struct inode *,struct dentry *,umode_t,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
  {
  	.read =		generic_read_dir,
0312fa7cc   Al Viro   [readdir] convert...
40
  	.iterate =	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,
f2963d455   Christoph Hellwig   jffs2: use generi...
57
  	.set_acl =	jffs2_set_acl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	.setattr =	jffs2_setattr,
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
59
60
61
62
  	.setxattr =	jffs2_setxattr,
  	.getxattr =	jffs2_getxattr,
  	.listxattr =	jffs2_listxattr,
  	.removexattr =	jffs2_removexattr
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
  };
  
  /***********************************************************************/
  
  
  /* We keep the dirent list sorted in increasing order of name hash,
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
69
     and we use the same hash function as the dentries. Makes this
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
     nice and simple
  */
  static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
00cd8dd3b   Al Viro   stop passing name...
73
  				   unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
  {
  	struct jffs2_inode_info *dir_f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
  	struct jffs2_full_dirent *fd = NULL, *fd_list;
  	uint32_t ino = 0;
  	struct inode *inode = NULL;
9c261b33a   Joe Perches   jffs2: Convert mo...
79
80
  	jffs2_dbg(1, "jffs2_lookup()
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

373d5e718   Richard Purdie   JFFS2: Return an ...
82
83
  	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
  		return ERR_PTR(-ENAMETOOLONG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  	dir_f = JFFS2_INODE_INFO(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

ced220703   David Woodhouse   [JFFS2] semaphore...
86
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
  
  	/* 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 ...
90
  		if (fd_list->nhash == target->d_name.hash &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
  		    (!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...
99
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  	if (ino) {
5451f79f5   David Howells   iget: stop JFFS2 ...
101
  		inode = jffs2_iget(dir_i->i_sb, ino);
a9049376e   Al Viro   make d_splice_ali...
102
  		if (IS_ERR(inode))
da320f055   Joe Perches   jffs2: Convert pr...
103
104
  			pr_warn("iget() failed for ino #%u
  ", ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	}
8966c5e0f   David Woodhouse   [JFFS2] Use d_spl...
106
  	return d_splice_alias(inode, target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
  }
  
  /***********************************************************************/
0312fa7cc   Al Viro   [readdir] convert...
110
  static int jffs2_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  {
0312fa7cc   Al Viro   [readdir] convert...
112
113
  	struct inode *inode = file_inode(file);
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	struct jffs2_full_dirent *fd;
0312fa7cc   Al Viro   [readdir] convert...
115
  	unsigned long curofs = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

0312fa7cc   Al Viro   [readdir] convert...
117
118
  	jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119

0312fa7cc   Al Viro   [readdir] convert...
120
121
  	if (!dir_emit_dots(file, ctx))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

ced220703   David Woodhouse   [JFFS2] semaphore...
123
  	mutex_lock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	for (fd = f->dents; fd; fd = fd->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  		curofs++;
0312fa7cc   Al Viro   [readdir] convert...
126
127
  		/* First loop: curofs = 2; pos = 2 */
  		if (curofs < ctx->pos) {
9c261b33a   Joe Perches   jffs2: Convert mo...
128
129
  			jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld
  ",
0312fa7cc   Al Viro   [readdir] convert...
130
  				  fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
  			continue;
  		}
  		if (!fd->ino) {
9c261b33a   Joe Perches   jffs2: Convert mo...
134
135
136
  			jffs2_dbg(2, "Skipping deletion dirent \"%s\"
  ",
  				  fd->name);
0312fa7cc   Al Viro   [readdir] convert...
137
  			ctx->pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  			continue;
  		}
9c261b33a   Joe Perches   jffs2: Convert mo...
140
141
  		jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d
  ",
0312fa7cc   Al Viro   [readdir] convert...
142
143
  			  (unsigned long)ctx->pos, fd->name, fd->ino, fd->type);
  		if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  			break;
0312fa7cc   Al Viro   [readdir] convert...
145
  		ctx->pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	}
ced220703   David Woodhouse   [JFFS2] semaphore...
147
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  	return 0;
  }
  
  /***********************************************************************/
4acdaf27e   Al Viro   switch ->create()...
152
  static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
ebfc3b49a   Al Viro   don't pass nameid...
153
  			umode_t mode, bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
  {
  	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 ...
164

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	c = JFFS2_SB_INFO(dir_i->i_sb);
9c261b33a   Joe Perches   jffs2: Convert mo...
166
167
  	jffs2_dbg(1, "%s()
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
169
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  
  	if (IS_ERR(inode)) {
9c261b33a   Joe Perches   jffs2: Convert mo...
172
173
  		jffs2_dbg(1, "jffs2_new_inode() failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
  		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...
185
186
187
188
189
190
  	/* 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: ...
191
  	ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
192
193
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
  
  	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
198

9c261b33a   Joe Perches   jffs2: Convert mo...
199
200
201
202
  	jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld
  ",
  		  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
  		  f->inocache->pino_nlink, inode->i_mapping->nrpages);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
203

e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
204
  	unlock_new_inode(inode);
8fc37ec54   Al Viro   don't expose I_NE...
205
  	d_instantiate(dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
207
208
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
209
  	iget_failed(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
210
211
  	jffs2_free_raw_inode(ri);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
  }
  
  /***********************************************************************/
  
  
  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);
2b0143b5c   David Howells   VFS: normal files...
221
  	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  	int ret;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
223
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
225
  	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
226
  			      dentry->d_name.len, dead_f, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	if (dead_f->inocache)
2b0143b5c   David Howells   VFS: normal files...
228
  		set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
229
230
  	if (!ret)
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
237
  	return ret;
  }
  /***********************************************************************/
  
  
  static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
238
239
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(d_inode(old_dentry)->i_sb);
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
  	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
  	int ret;
  	uint8_t type;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
243
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
  
  	/* Don't let people make hard links to bad inodes. */
  	if (!f->inocache)
  		return -EIO;
e36cb0b89   David Howells   VFS: (Scripted) C...
248
  	if (d_is_dir(old_dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
  		return -EPERM;
  
  	/* XXX: This is ugly */
2b0143b5c   David Howells   VFS: normal files...
252
  	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  	if (!type) type = DT_REG;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
254
255
  	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
256
257
  
  	if (!ret) {
ced220703   David Woodhouse   [JFFS2] semaphore...
258
  		mutex_lock(&f->sem);
2b0143b5c   David Howells   VFS: normal files...
259
  		set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink);
ced220703   David Woodhouse   [JFFS2] semaphore...
260
  		mutex_unlock(&f->sem);
2b0143b5c   David Howells   VFS: normal files...
261
  		d_instantiate(dentry, d_inode(old_dentry));
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
262
  		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2b0143b5c   David Howells   VFS: normal files...
263
  		ihold(d_inode(old_dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  	}
  	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...
280
  	uint32_t alloclen;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
281
  	int ret, targetlen = strlen(target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  
  	/* 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...
285
  	if (targetlen > 254)
bde86fec7   Adrian Hunter   [JFFS2] Correct s...
286
  		return -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
  
  	ri = jffs2_alloc_raw_inode();
  
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
292

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
294
295
296
  
  	/* 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
297
298
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
299
300
  	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
306
  	inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
  
  	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...
317
  	inode->i_size = targetlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
  	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...
323
  	ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
325

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
326
  	fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
332
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
334
335
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  	}
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
337

2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
338
  	/* We use f->target field to store the target path. */
04aadf36d   Julia Lawall   jffs2: use kmemdup
339
  	f->target = kmemdup(target, targetlen + 1, GFP_KERNEL);
2b79adcca   Artem B. Bityutskiy   [JFFS2] Use f->ta...
340
  	if (!f->target) {
da320f055   Joe Perches   jffs2: Convert pr...
341
342
  		pr_warn("Can't allocate %d bytes of memory
  ", targetlen + 1);
ced220703   David Woodhouse   [JFFS2] semaphore...
343
  		mutex_unlock(&f->sem);
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
344
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
345
346
  		ret = -ENOMEM;
  		goto fail;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
347
  	}
a8db149fc   Al Viro   jffs2: switch to ...
348
  	inode->i_link = f->target;
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
349

9c261b33a   Joe Perches   jffs2: Convert mo...
350
351
352
  	jffs2_dbg(1, "%s(): symlink's target '%s' cached
  ",
  		  __func__, (char *)f->target);
32f1a95d5   Artem B. Bityuckiy   [JFFS2] Add symli...
353

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
354
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
358
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
361

2a7dba391   Eric Paris   fs/vfs/security: ...
362
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
363
364
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
365
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
366
367
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
368

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	c = JFFS2_SB_INFO(dir_i->i_sb);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
447
448
  	/* 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
449
450
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
451
452
  	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
  				  JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
458
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
  
  	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
468
469
  
  	f = JFFS2_INODE_INFO(inode);
27c72b040   David Woodhouse   [JFFS2] Track par...
470
  	/* Directories get nlink 2 at start */
bfe868486   Miklos Szeredi   filesystems: add ...
471
  	set_nlink(inode, 2);
27c72b040   David Woodhouse   [JFFS2] Track par...
472
473
  	/* but ic->pino_nlink is the parent ino# */
  	f->inocache->pino_nlink = dir_i->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
  	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 ...
476

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
477
  	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
482
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
483
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
485
486
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
488
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
492
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
495

2a7dba391   Eric Paris   fs/vfs/security: ...
496
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
497
498
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
499
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
500
501
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
502

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
  	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...
512
513
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
517
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  
  	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...
532
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
533

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
535
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
539
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
540
541
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
  	}
  
  	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
545
  	inc_nlink(dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
551
  
  	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...
552
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	jffs2_complete_reservation(c);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
554
  	unlock_new_inode(inode);
8fc37ec54   Al Viro   don't expose I_NE...
555
  	d_instantiate(dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
557
558
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
559
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
560
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
  }
  
  static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
  {
27c72b040   David Woodhouse   [JFFS2] Track par...
565
566
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
  	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2b0143b5c   David Howells   VFS: normal files...
567
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	struct jffs2_full_dirent *fd;
  	int ret;
27c72b040   David Woodhouse   [JFFS2] Track par...
570
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
  
  	for (fd = f->dents ; fd; fd = fd->next) {
  		if (fd->ino)
  			return -ENOTEMPTY;
  	}
27c72b040   David Woodhouse   [JFFS2] Track par...
576
577
578
579
580
  
  	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);
2b0143b5c   David Howells   VFS: normal files...
581
  		clear_nlink(d_inode(dentry));
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
582
  		drop_nlink(dir_i);
27c72b040   David Woodhouse   [JFFS2] Track par...
583
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
  	return ret;
  }
1a67aafb5   Al Viro   switch ->mknod() ...
586
  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
587
588
589
590
591
592
593
594
595
  {
  	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...
596
  	union jffs2_device_node dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  	int devlen = 0;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
598
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
603

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

aef9ab478   David Woodhouse   [JFFS2] Support n...
606
607
  	if (S_ISBLK(mode) || S_ISCHR(mode))
  		devlen = jffs2_encode_dev(&dev, rdev);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
608
609
610
  
  	/* 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
611
612
  	 */
  	namelen = dentry->d_name.len;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
613
  	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
aef9ab478   David Woodhouse   [JFFS2] Support n...
614
  				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
619
  
  	if (ret) {
  		jffs2_free_raw_inode(ri);
  		return ret;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
620
  	inode = jffs2_new_inode(dir_i, mode, ri);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  
  	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 ...
639

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
640
  	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
  
  	jffs2_free_raw_inode(ri);
  
  	if (IS_ERR(fn)) {
  		/* Eeek. Wave bye bye */
ced220703   David Woodhouse   [JFFS2] semaphore...
646
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  		jffs2_complete_reservation(c);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
648
649
  		ret = PTR_ERR(fn);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
651
  	/* No data here. Only a metadata node, which will be
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
  	   obsoleted by the first data write
  	*/
  	f->metadata = fn;
ced220703   David Woodhouse   [JFFS2] semaphore...
655
  	mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  
  	jffs2_complete_reservation(c);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
658

2a7dba391   Eric Paris   fs/vfs/security: ...
659
  	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
660
661
  	if (ret)
  		goto fail;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
662
  	ret = jffs2_init_acl_post(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
663
664
  	if (ret)
  		goto fail;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
665

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
666
667
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
668
669
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
  
  	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...
675
676
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
680
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
  
  	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...
698
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
699

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
701
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
705
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
706
707
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
  	}
  
  	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...
717
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  	jffs2_complete_reservation(c);
e72e6497e   David Woodhouse   jffs2: Fix NFS ra...
719
  	unlock_new_inode(inode);
8fc37ec54   Al Viro   don't expose I_NE...
720
  	d_instantiate(dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
722
723
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
724
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
725
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
  }
  
  static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
729
  			 struct inode *new_dir_i, struct dentry *new_dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
734
  {
  	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...
735
  	uint32_t now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
737
  	/* The VFS will check for us and prevent trying to rename a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
  	 * 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.
  	 */
2b0143b5c   David Howells   VFS: normal files...
742
743
  	if (d_really_is_positive(new_dentry)) {
  		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
e36cb0b89   David Howells   VFS: (Scripted) C...
744
  		if (d_is_dir(new_dentry)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  			struct jffs2_full_dirent *fd;
ced220703   David Woodhouse   [JFFS2] semaphore...
746
  			mutex_lock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  			for (fd = victim_f->dents; fd; fd = fd->next) {
  				if (fd->ino) {
ced220703   David Woodhouse   [JFFS2] semaphore...
749
  					mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
  					return -ENOTEMPTY;
  				}
  			}
ced220703   David Woodhouse   [JFFS2] semaphore...
753
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
  		}
  	}
  
  	/* XXX: We probably ought to alloc enough space for
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
758
  	   both nodes at the same time. Writing the new link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
  	   then getting -ENOSPC, is quite bad :)
  	*/
  
  	/* Make a hard link */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
763

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  	/* XXX: This is ugly */
2b0143b5c   David Howells   VFS: normal files...
765
  	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
  	if (!type) type = DT_REG;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
767
  	now = get_seconds();
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
768
  	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
2b0143b5c   David Howells   VFS: normal files...
769
  			    d_inode(old_dentry)->i_ino, type,
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
770
  			    new_dentry->d_name.name, new_dentry->d_name.len, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
776
  
  	if (ret)
  		return ret;
  
  	if (victim_f) {
  		/* There was a victim. Kill it off nicely */
e36cb0b89   David Howells   VFS: (Scripted) C...
777
  		if (d_is_dir(new_dentry))
2b0143b5c   David Howells   VFS: normal files...
778
  			clear_nlink(d_inode(new_dentry));
22ba747f6   Al Viro   jffs2: fix IN_DEL...
779
  		else
2b0143b5c   David Howells   VFS: normal files...
780
  			drop_nlink(d_inode(new_dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
  		/* 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...
784
  			mutex_lock(&victim_f->sem);
e36cb0b89   David Howells   VFS: (Scripted) C...
785
  			if (d_is_dir(new_dentry))
27c72b040   David Woodhouse   [JFFS2] Track par...
786
787
788
  				victim_f->inocache->pino_nlink = 0;
  			else
  				victim_f->inocache->pino_nlink--;
ced220703   David Woodhouse   [JFFS2] semaphore...
789
  			mutex_unlock(&victim_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
  		}
  	}
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
792
  	/* If it was a directory we moved, and there was no victim,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  	   increase i_nlink on its new parent */
e36cb0b89   David Howells   VFS: (Scripted) C...
794
  	if (d_is_dir(old_dentry) && !victim_f)
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
795
  		inc_nlink(new_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
  
  	/* Unlink the original */
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
798
  	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
799
  			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
804
  
  	/* We don't touch inode->i_nlink */
  
  	if (ret) {
  		/* Oh shit. We really ought to make a single node which can do both atomically */
2b0143b5c   David Howells   VFS: normal files...
805
  		struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
ced220703   David Woodhouse   [JFFS2] semaphore...
806
  		mutex_lock(&f->sem);
2b0143b5c   David Howells   VFS: normal files...
807
  		inc_nlink(d_inode(old_dentry));
e36cb0b89   David Howells   VFS: (Scripted) C...
808
  		if (f->inocache && !d_is_dir(old_dentry))
27c72b040   David Woodhouse   [JFFS2] Track par...
809
  			f->inocache->pino_nlink++;
ced220703   David Woodhouse   [JFFS2] semaphore...
810
  		mutex_unlock(&f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811

da320f055   Joe Perches   jffs2: Convert pr...
812
813
814
  		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link
  ",
  			  __func__, ret);
f93812846   Al Viro   jffs2: reduce the...
815
816
817
818
819
820
821
822
  		/*
  		 * We can't keep the target in dcache after that.
  		 * For one thing, we can't afford dentry aliases for directories.
  		 * For another, if there was a victim, we _can't_ set new inode
  		 * for that sucker and we have to trigger mount eviction - the
  		 * caller won't do it on its own since we are returning an error.
  		 */
  		d_invalidate(new_dentry);
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
823
  		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
  		return ret;
  	}
e36cb0b89   David Howells   VFS: (Scripted) C...
826
  	if (d_is_dir(old_dentry))
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
827
  		drop_nlink(old_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828

3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
829
  	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
830
831
  	return 0;
  }