Blame view

fs/jffs2/dir.c 22.6 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 *,
f03b8ad8d   Miklos Szeredi   fs: support RENAM...
35
36
  			 struct inode *, struct dentry *,
  			 unsigned int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
38
  const struct file_operations jffs2_dir_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  {
  	.read =		generic_read_dir,
c51da20c4   Al Viro   more trivial ->it...
41
  	.iterate_shared=jffs2_readdir,
0533400b7   Stoyan Gaydarov   [JFFS2] Use .unlo...
42
  	.unlocked_ioctl=jffs2_ioctl,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
43
44
  	.fsync =	jffs2_fsync,
  	.llseek =	generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
46
  const struct inode_operations jffs2_dir_inode_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  {
265489f01   David Woodhouse   [JFFS2] Remove co...
48
49
  	.create =	jffs2_create,
  	.lookup =	jffs2_lookup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
56
  	.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 ...
57
  	.get_acl =	jffs2_get_acl,
f2963d455   Christoph Hellwig   jffs2: use generi...
58
  	.set_acl =	jffs2_set_acl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  	.setattr =	jffs2_setattr,
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
60
  	.listxattr =	jffs2_listxattr,
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
     nice and simple
  */
  static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
00cd8dd3b   Al Viro   stop passing name...
71
  				   unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  {
  	struct jffs2_inode_info *dir_f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
  	struct jffs2_full_dirent *fd = NULL, *fd_list;
  	uint32_t ino = 0;
  	struct inode *inode = NULL;
8387ff257   Linus Torvalds   vfs: make the str...
77
  	unsigned int nhash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

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

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

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

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

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

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

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

9c261b33a   Joe Perches   jffs2: Convert mo...
201
202
203
204
  	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...
205

f440ea85d   Al Viro   do d_instantiate/...
206
  	d_instantiate_new(dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
208
209
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
210
  	iget_failed(inode);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
211
212
  	jffs2_free_raw_inode(ri);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
221
  }
  
  /***********************************************************************/
  
  
  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...
222
  	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	int ret;
3a69e0cd2   Artem B. Bityutskiy   [JFFS2] Fix JFFS2...
224
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

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

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

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

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

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

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

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

9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
370
371
  	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
  				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
372
373
  	if (ret)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
  
  	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...
379
380
  		ret = -ENOMEM;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
  	}
  
  	dir_f = JFFS2_INODE_INFO(dir_i);
ced220703   David Woodhouse   [JFFS2] semaphore...
384
  	mutex_lock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  
  	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...
399
  	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  
  	if (IS_ERR(fd)) {
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
402
  		/* dirent failed to write. Delete the inode normally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
  		   as if it were the final unlink() */
  		jffs2_complete_reservation(c);
  		jffs2_free_raw_dirent(rd);
ced220703   David Woodhouse   [JFFS2] semaphore...
406
  		mutex_unlock(&dir_f->sem);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
407
408
  		ret = PTR_ERR(fd);
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
416
417
  	}
  
  	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...
418
  	mutex_unlock(&dir_f->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  	jffs2_complete_reservation(c);
f440ea85d   Al Viro   do d_instantiate/...
420
  	d_instantiate_new(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);
f440ea85d   Al Viro   do d_instantiate/...
554
  	d_instantiate_new(dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  	return 0;
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
556
557
  
   fail:
41cce647f   Al Viro   jffs2: don't open...
558
  	iget_failed(inode);
f324e4cb2   David Woodhouse   jffs2: Fix in-cor...
559
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
  }
  
  static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
  {
27c72b040   David Woodhouse   [JFFS2] Track par...
564
565
  	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...
566
  	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
  	struct jffs2_full_dirent *fd;
  	int ret;
27c72b040   David Woodhouse   [JFFS2] Track par...
569
  	uint32_t now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
  
  	for (fd = f->dents ; fd; fd = fd->next) {
  		if (fd->ino)
  			return -ENOTEMPTY;
  	}
27c72b040   David Woodhouse   [JFFS2] Track par...
575
576
577
578
579
  
  	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...
580
  		clear_nlink(d_inode(dentry));
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
581
  		drop_nlink(dir_i);
27c72b040   David Woodhouse   [JFFS2] Track par...
582
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
  	return ret;
  }
1a67aafb5   Al Viro   switch ->mknod() ...
585
  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
586
587
588
589
590
591
592
593
594
  {
  	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...
595
  	union jffs2_device_node dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  	int devlen = 0;
9fe4854cd   David Woodhouse   [JFFS2] Remove fl...
597
  	uint32_t alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  	ri = jffs2_alloc_raw_inode();
  	if (!ri)
  		return -ENOMEM;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
602

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

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

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

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

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

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

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

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

da320f055   Joe Perches   jffs2: Convert pr...
813
814
815
  		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link
  ",
  			  __func__, ret);
f93812846   Al Viro   jffs2: reduce the...
816
817
818
819
820
821
822
823
  		/*
  		 * 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...
824
  		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
  		return ret;
  	}
e36cb0b89   David Howells   VFS: (Scripted) C...
827
  	if (d_is_dir(old_dentry))
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
828
  		drop_nlink(old_dir_i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829

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