xref: /openbmc/linux/fs/jffs2/dir.c (revision f03b8ad8)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * JFFS2 -- Journalling Flash File System, Version 2.
31da177e4SLinus Torvalds  *
4c00c310eSDavid Woodhouse  * Copyright © 2001-2007 Red Hat, Inc.
56088c058SDavid Woodhouse  * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Created by David Woodhouse <dwmw2@infradead.org>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * For licensing information, see the file 'LICENCE' in this directory.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
135a528957SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
145a528957SJoe Perches 
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/fs.h>
181da177e4SLinus Torvalds #include <linux/crc32.h>
191da177e4SLinus Torvalds #include <linux/jffs2.h>
20cbb9a561SDavid Woodhouse #include "jffs2_fs_i.h"
21cbb9a561SDavid Woodhouse #include "jffs2_fs_sb.h"
221da177e4SLinus Torvalds #include <linux/time.h>
231da177e4SLinus Torvalds #include "nodelist.h"
241da177e4SLinus Torvalds 
250312fa7cSAl Viro static int jffs2_readdir (struct file *, struct dir_context *);
261da177e4SLinus Torvalds 
274acdaf27SAl Viro static int jffs2_create (struct inode *,struct dentry *,umode_t,
28ebfc3b49SAl Viro 			 bool);
291da177e4SLinus Torvalds static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
3000cd8dd3SAl Viro 				    unsigned int);
311da177e4SLinus Torvalds static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
321da177e4SLinus Torvalds static int jffs2_unlink (struct inode *,struct dentry *);
331da177e4SLinus Torvalds static int jffs2_symlink (struct inode *,struct dentry *,const char *);
3418bb1db3SAl Viro static int jffs2_mkdir (struct inode *,struct dentry *,umode_t);
351da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *,struct dentry *);
361a67aafbSAl Viro static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
371da177e4SLinus Torvalds static int jffs2_rename (struct inode *, struct dentry *,
38f03b8ad8SMiklos Szeredi 			 struct inode *, struct dentry *,
39f03b8ad8SMiklos Szeredi 			 unsigned int);
401da177e4SLinus Torvalds 
414b6f5d20SArjan van de Ven const struct file_operations jffs2_dir_operations =
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds 	.read =		generic_read_dir,
44c51da20cSAl Viro 	.iterate_shared=jffs2_readdir,
450533400bSStoyan Gaydarov 	.unlocked_ioctl=jffs2_ioctl,
463222a3e5SChristoph Hellwig 	.fsync =	jffs2_fsync,
473222a3e5SChristoph Hellwig 	.llseek =	generic_file_llseek,
481da177e4SLinus Torvalds };
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 
5192e1d5beSArjan van de Ven const struct inode_operations jffs2_dir_inode_operations =
521da177e4SLinus Torvalds {
53265489f0SDavid Woodhouse 	.create =	jffs2_create,
54265489f0SDavid Woodhouse 	.lookup =	jffs2_lookup,
551da177e4SLinus Torvalds 	.link =		jffs2_link,
561da177e4SLinus Torvalds 	.unlink =	jffs2_unlink,
571da177e4SLinus Torvalds 	.symlink =	jffs2_symlink,
581da177e4SLinus Torvalds 	.mkdir =	jffs2_mkdir,
591da177e4SLinus Torvalds 	.rmdir =	jffs2_rmdir,
601da177e4SLinus Torvalds 	.mknod =	jffs2_mknod,
61f03b8ad8SMiklos Szeredi 	.rename2 =	jffs2_rename,
624e34e719SChristoph Hellwig 	.get_acl =	jffs2_get_acl,
63f2963d45SChristoph Hellwig 	.set_acl =	jffs2_set_acl,
641da177e4SLinus Torvalds 	.setattr =	jffs2_setattr,
65aa98d7cfSKaiGai Kohei 	.setxattr =	jffs2_setxattr,
66aa98d7cfSKaiGai Kohei 	.getxattr =	jffs2_getxattr,
67aa98d7cfSKaiGai Kohei 	.listxattr =	jffs2_listxattr,
68aa98d7cfSKaiGai Kohei 	.removexattr =	jffs2_removexattr
691da177e4SLinus Torvalds };
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /***********************************************************************/
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds /* We keep the dirent list sorted in increasing order of name hash,
751da177e4SLinus Torvalds    and we use the same hash function as the dentries. Makes this
761da177e4SLinus Torvalds    nice and simple
771da177e4SLinus Torvalds */
781da177e4SLinus Torvalds static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
7900cd8dd3SAl Viro 				   unsigned int flags)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	struct jffs2_inode_info *dir_f;
821da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd = NULL, *fd_list;
831da177e4SLinus Torvalds 	uint32_t ino = 0;
841da177e4SLinus Torvalds 	struct inode *inode = NULL;
858387ff25SLinus Torvalds 	unsigned int nhash;
861da177e4SLinus Torvalds 
879c261b33SJoe Perches 	jffs2_dbg(1, "jffs2_lookup()\n");
881da177e4SLinus Torvalds 
89373d5e71SRichard Purdie 	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
90373d5e71SRichard Purdie 		return ERR_PTR(-ENAMETOOLONG);
91373d5e71SRichard Purdie 
921da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
931da177e4SLinus Torvalds 
948387ff25SLinus Torvalds 	/* The 'nhash' on the fd_list is not the same as the dentry hash */
958387ff25SLinus Torvalds 	nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len);
968387ff25SLinus Torvalds 
97ced22070SDavid Woodhouse 	mutex_lock(&dir_f->sem);
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
1008387ff25SLinus Torvalds 	for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
1018387ff25SLinus Torvalds 		if (fd_list->nhash == nhash &&
1021da177e4SLinus Torvalds 		    (!fd || fd_list->version > fd->version) &&
1031da177e4SLinus Torvalds 		    strlen(fd_list->name) == target->d_name.len &&
1041da177e4SLinus Torvalds 		    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
1051da177e4SLinus Torvalds 			fd = fd_list;
1061da177e4SLinus Torvalds 		}
1071da177e4SLinus Torvalds 	}
1081da177e4SLinus Torvalds 	if (fd)
1091da177e4SLinus Torvalds 		ino = fd->ino;
110ced22070SDavid Woodhouse 	mutex_unlock(&dir_f->sem);
1111da177e4SLinus Torvalds 	if (ino) {
1125451f79fSDavid Howells 		inode = jffs2_iget(dir_i->i_sb, ino);
113a9049376SAl Viro 		if (IS_ERR(inode))
114da320f05SJoe Perches 			pr_warn("iget() failed for ino #%u\n", ino);
1151da177e4SLinus Torvalds 	}
1161da177e4SLinus Torvalds 
1178966c5e0SDavid Woodhouse 	return d_splice_alias(inode, target);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds /***********************************************************************/
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 
1230312fa7cSAl Viro static int jffs2_readdir(struct file *file, struct dir_context *ctx)
1241da177e4SLinus Torvalds {
1250312fa7cSAl Viro 	struct inode *inode = file_inode(file);
1260312fa7cSAl Viro 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1271da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
1280312fa7cSAl Viro 	unsigned long curofs = 1;
1291da177e4SLinus Torvalds 
1300312fa7cSAl Viro 	jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino);
1311da177e4SLinus Torvalds 
1320312fa7cSAl Viro 	if (!dir_emit_dots(file, ctx))
1330312fa7cSAl Viro 		return 0;
1341da177e4SLinus Torvalds 
135ced22070SDavid Woodhouse 	mutex_lock(&f->sem);
1361da177e4SLinus Torvalds 	for (fd = f->dents; fd; fd = fd->next) {
1371da177e4SLinus Torvalds 		curofs++;
1380312fa7cSAl Viro 		/* First loop: curofs = 2; pos = 2 */
1390312fa7cSAl Viro 		if (curofs < ctx->pos) {
1409c261b33SJoe Perches 			jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
1410312fa7cSAl Viro 				  fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos);
1421da177e4SLinus Torvalds 			continue;
1431da177e4SLinus Torvalds 		}
1441da177e4SLinus Torvalds 		if (!fd->ino) {
1459c261b33SJoe Perches 			jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
1469c261b33SJoe Perches 				  fd->name);
1470312fa7cSAl Viro 			ctx->pos++;
1481da177e4SLinus Torvalds 			continue;
1491da177e4SLinus Torvalds 		}
1509c261b33SJoe Perches 		jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
1510312fa7cSAl Viro 			  (unsigned long)ctx->pos, fd->name, fd->ino, fd->type);
1520312fa7cSAl Viro 		if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type))
1531da177e4SLinus Torvalds 			break;
1540312fa7cSAl Viro 		ctx->pos++;
1551da177e4SLinus Torvalds 	}
156ced22070SDavid Woodhouse 	mutex_unlock(&f->sem);
1571da177e4SLinus Torvalds 	return 0;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /***********************************************************************/
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 
1634acdaf27SAl Viro static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
164ebfc3b49SAl Viro 			umode_t mode, bool excl)
1651da177e4SLinus Torvalds {
1661da177e4SLinus Torvalds 	struct jffs2_raw_inode *ri;
1671da177e4SLinus Torvalds 	struct jffs2_inode_info *f, *dir_f;
1681da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
1691da177e4SLinus Torvalds 	struct inode *inode;
1701da177e4SLinus Torvalds 	int ret;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	ri = jffs2_alloc_raw_inode();
1731da177e4SLinus Torvalds 	if (!ri)
1741da177e4SLinus Torvalds 		return -ENOMEM;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	c = JFFS2_SB_INFO(dir_i->i_sb);
1771da177e4SLinus Torvalds 
1789c261b33SJoe Perches 	jffs2_dbg(1, "%s()\n", __func__);
1791da177e4SLinus Torvalds 
180cfc8dc6fSKaiGai Kohei 	inode = jffs2_new_inode(dir_i, mode, ri);
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	if (IS_ERR(inode)) {
1839c261b33SJoe Perches 		jffs2_dbg(1, "jffs2_new_inode() failed\n");
1841da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
1851da177e4SLinus Torvalds 		return PTR_ERR(inode);
1861da177e4SLinus Torvalds 	}
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	inode->i_op = &jffs2_file_inode_operations;
1891da177e4SLinus Torvalds 	inode->i_fop = &jffs2_file_operations;
1901da177e4SLinus Torvalds 	inode->i_mapping->a_ops = &jffs2_file_address_operations;
1911da177e4SLinus Torvalds 	inode->i_mapping->nrpages = 0;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	f = JFFS2_INODE_INFO(inode);
1941da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
1951da177e4SLinus Torvalds 
196590fe34cSDavid Woodhouse 	/* jffs2_do_create() will want to lock it, _after_ reserving
197590fe34cSDavid Woodhouse 	   space and taking c-alloc_sem. If we keep it locked here,
198590fe34cSDavid Woodhouse 	   lockdep gets unhappy (although it's a false positive;
199590fe34cSDavid Woodhouse 	   nothing else will be looking at this inode yet so there's
200590fe34cSDavid Woodhouse 	   no chance of AB-BA deadlock involving its f->sem). */
201590fe34cSDavid Woodhouse 	mutex_unlock(&f->sem);
202590fe34cSDavid Woodhouse 
2032a7dba39SEric Paris 	ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
204aa98d7cfSKaiGai Kohei 	if (ret)
205aa98d7cfSKaiGai Kohei 		goto fail;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	jffs2_free_raw_inode(ri);
2101da177e4SLinus Torvalds 
2119c261b33SJoe Perches 	jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
2129c261b33SJoe Perches 		  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
2139c261b33SJoe Perches 		  f->inocache->pino_nlink, inode->i_mapping->nrpages);
214e72e6497SDavid Woodhouse 
215e72e6497SDavid Woodhouse 	unlock_new_inode(inode);
2168fc37ec5SAl Viro 	d_instantiate(dentry, inode);
2171da177e4SLinus Torvalds 	return 0;
218aa98d7cfSKaiGai Kohei 
219aa98d7cfSKaiGai Kohei  fail:
22041cce647SAl Viro 	iget_failed(inode);
221aa98d7cfSKaiGai Kohei 	jffs2_free_raw_inode(ri);
222aa98d7cfSKaiGai Kohei 	return ret;
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds /***********************************************************************/
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
2311da177e4SLinus Torvalds 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2322b0143b5SDavid Howells 	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry));
2331da177e4SLinus Torvalds 	int ret;
2343a69e0cdSArtem B. Bityutskiy 	uint32_t now = get_seconds();
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
2373a69e0cdSArtem B. Bityutskiy 			      dentry->d_name.len, dead_f, now);
2381da177e4SLinus Torvalds 	if (dead_f->inocache)
2392b0143b5SDavid Howells 		set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink);
2403a69e0cdSArtem B. Bityutskiy 	if (!ret)
2413a69e0cdSArtem B. Bityutskiy 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2421da177e4SLinus Torvalds 	return ret;
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds /***********************************************************************/
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
2481da177e4SLinus Torvalds {
249fc64005cSAl Viro 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb);
2502b0143b5SDavid Howells 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
2511da177e4SLinus Torvalds 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2521da177e4SLinus Torvalds 	int ret;
2531da177e4SLinus Torvalds 	uint8_t type;
2543a69e0cdSArtem B. Bityutskiy 	uint32_t now;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	/* Don't let people make hard links to bad inodes. */
2571da177e4SLinus Torvalds 	if (!f->inocache)
2581da177e4SLinus Torvalds 		return -EIO;
2591da177e4SLinus Torvalds 
260e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry))
2611da177e4SLinus Torvalds 		return -EPERM;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	/* XXX: This is ugly */
2642b0143b5SDavid Howells 	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
2651da177e4SLinus Torvalds 	if (!type) type = DT_REG;
2661da177e4SLinus Torvalds 
2673a69e0cdSArtem B. Bityutskiy 	now = get_seconds();
2683a69e0cdSArtem B. Bityutskiy 	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	if (!ret) {
271ced22070SDavid Woodhouse 		mutex_lock(&f->sem);
2722b0143b5SDavid Howells 		set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink);
273ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
2742b0143b5SDavid Howells 		d_instantiate(dentry, d_inode(old_dentry));
2753a69e0cdSArtem B. Bityutskiy 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2762b0143b5SDavid Howells 		ihold(d_inode(old_dentry));
2771da177e4SLinus Torvalds 	}
2781da177e4SLinus Torvalds 	return ret;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds /***********************************************************************/
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	struct jffs2_inode_info *f, *dir_f;
2861da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
2871da177e4SLinus Torvalds 	struct inode *inode;
2881da177e4SLinus Torvalds 	struct jffs2_raw_inode *ri;
2891da177e4SLinus Torvalds 	struct jffs2_raw_dirent *rd;
2901da177e4SLinus Torvalds 	struct jffs2_full_dnode *fn;
2911da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
2921da177e4SLinus Torvalds 	int namelen;
2939fe4854cSDavid Woodhouse 	uint32_t alloclen;
29432f1a95dSArtem B. Bityuckiy 	int ret, targetlen = strlen(target);
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	/* FIXME: If you care. We'd need to use frags for the target
2971da177e4SLinus Torvalds 	   if it grows much more than this */
29832f1a95dSArtem B. Bityuckiy 	if (targetlen > 254)
299bde86fecSAdrian Hunter 		return -ENAMETOOLONG;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	ri = jffs2_alloc_raw_inode();
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	if (!ri)
3041da177e4SLinus Torvalds 		return -ENOMEM;
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	c = JFFS2_SB_INFO(dir_i->i_sb);
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	/* Try to reserve enough space for both node and dirent.
3091da177e4SLinus Torvalds 	 * Just the node will do for now, though
3101da177e4SLinus Torvalds 	 */
3111da177e4SLinus Torvalds 	namelen = dentry->d_name.len;
3129fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen,
313e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	if (ret) {
3161da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
3171da177e4SLinus Torvalds 		return ret;
3181da177e4SLinus Torvalds 	}
3191da177e4SLinus Torvalds 
320cfc8dc6fSKaiGai Kohei 	inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	if (IS_ERR(inode)) {
3231da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
3241da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
3251da177e4SLinus Torvalds 		return PTR_ERR(inode);
3261da177e4SLinus Torvalds 	}
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	inode->i_op = &jffs2_symlink_inode_operations;
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	f = JFFS2_INODE_INFO(inode);
3311da177e4SLinus Torvalds 
33232f1a95dSArtem B. Bityuckiy 	inode->i_size = targetlen;
3331da177e4SLinus Torvalds 	ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
3341da177e4SLinus Torvalds 	ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
3351da177e4SLinus Torvalds 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	ri->compr = JFFS2_COMPR_NONE;
33832f1a95dSArtem B. Bityuckiy 	ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
3391da177e4SLinus Torvalds 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
3401da177e4SLinus Torvalds 
3419fe4854cSDavid Woodhouse 	fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL);
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	jffs2_free_raw_inode(ri);
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	if (IS_ERR(fn)) {
3461da177e4SLinus Torvalds 		/* Eeek. Wave bye bye */
347ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
3481da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
349f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fn);
350f324e4cbSDavid Woodhouse 		goto fail;
3511da177e4SLinus Torvalds 	}
35232f1a95dSArtem B. Bityuckiy 
3532b79adccSArtem B. Bityutskiy 	/* We use f->target field to store the target path. */
35404aadf36SJulia Lawall 	f->target = kmemdup(target, targetlen + 1, GFP_KERNEL);
3552b79adccSArtem B. Bityutskiy 	if (!f->target) {
356da320f05SJoe Perches 		pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1);
357ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
35832f1a95dSArtem B. Bityuckiy 		jffs2_complete_reservation(c);
359f324e4cbSDavid Woodhouse 		ret = -ENOMEM;
360f324e4cbSDavid Woodhouse 		goto fail;
36132f1a95dSArtem B. Bityuckiy 	}
362a8db149fSAl Viro 	inode->i_link = f->target;
36332f1a95dSArtem B. Bityuckiy 
3649c261b33SJoe Perches 	jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
3659c261b33SJoe Perches 		  __func__, (char *)f->target);
36632f1a95dSArtem B. Bityuckiy 
3671da177e4SLinus Torvalds 	/* No data here. Only a metadata node, which will be
3681da177e4SLinus Torvalds 	   obsoleted by the first data write
3691da177e4SLinus Torvalds 	*/
3701da177e4SLinus Torvalds 	f->metadata = fn;
371ced22070SDavid Woodhouse 	mutex_unlock(&f->sem);
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
374aa98d7cfSKaiGai Kohei 
3752a7dba39SEric Paris 	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
376f324e4cbSDavid Woodhouse 	if (ret)
377f324e4cbSDavid Woodhouse 		goto fail;
378f324e4cbSDavid Woodhouse 
379cfc8dc6fSKaiGai Kohei 	ret = jffs2_init_acl_post(inode);
380f324e4cbSDavid Woodhouse 	if (ret)
381f324e4cbSDavid Woodhouse 		goto fail;
382aa98d7cfSKaiGai Kohei 
3839fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
384e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
385f324e4cbSDavid Woodhouse 	if (ret)
386f324e4cbSDavid Woodhouse 		goto fail;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	rd = jffs2_alloc_raw_dirent();
3891da177e4SLinus Torvalds 	if (!rd) {
3901da177e4SLinus Torvalds 		/* Argh. Now we treat it like a normal delete */
3911da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
392f324e4cbSDavid Woodhouse 		ret = -ENOMEM;
393f324e4cbSDavid Woodhouse 		goto fail;
3941da177e4SLinus Torvalds 	}
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
397ced22070SDavid Woodhouse 	mutex_lock(&dir_f->sem);
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
4001da177e4SLinus Torvalds 	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
4011da177e4SLinus Torvalds 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
4021da177e4SLinus Torvalds 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	rd->pino = cpu_to_je32(dir_i->i_ino);
4051da177e4SLinus Torvalds 	rd->version = cpu_to_je32(++dir_f->highest_version);
4061da177e4SLinus Torvalds 	rd->ino = cpu_to_je32(inode->i_ino);
4071da177e4SLinus Torvalds 	rd->mctime = cpu_to_je32(get_seconds());
4081da177e4SLinus Torvalds 	rd->nsize = namelen;
4091da177e4SLinus Torvalds 	rd->type = DT_LNK;
4101da177e4SLinus Torvalds 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
4111da177e4SLinus Torvalds 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
4121da177e4SLinus Torvalds 
4139fe4854cSDavid Woodhouse 	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	if (IS_ERR(fd)) {
4161da177e4SLinus Torvalds 		/* dirent failed to write. Delete the inode normally
4171da177e4SLinus Torvalds 		   as if it were the final unlink() */
4181da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
4191da177e4SLinus Torvalds 		jffs2_free_raw_dirent(rd);
420ced22070SDavid Woodhouse 		mutex_unlock(&dir_f->sem);
421f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fd);
422f324e4cbSDavid Woodhouse 		goto fail;
4231da177e4SLinus Torvalds 	}
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	jffs2_free_raw_dirent(rd);
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	/* Link the fd into the inode's list, obsoleting an old
4301da177e4SLinus Torvalds 	   one if necessary. */
4311da177e4SLinus Torvalds 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
4321da177e4SLinus Torvalds 
433ced22070SDavid Woodhouse 	mutex_unlock(&dir_f->sem);
4341da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
4351da177e4SLinus Torvalds 
436e72e6497SDavid Woodhouse 	unlock_new_inode(inode);
4378fc37ec5SAl Viro 	d_instantiate(dentry, inode);
4381da177e4SLinus Torvalds 	return 0;
439f324e4cbSDavid Woodhouse 
440f324e4cbSDavid Woodhouse  fail:
44141cce647SAl Viro 	iget_failed(inode);
442f324e4cbSDavid Woodhouse 	return ret;
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 
44618bb1db3SAl Viro static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode)
4471da177e4SLinus Torvalds {
4481da177e4SLinus Torvalds 	struct jffs2_inode_info *f, *dir_f;
4491da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
4501da177e4SLinus Torvalds 	struct inode *inode;
4511da177e4SLinus Torvalds 	struct jffs2_raw_inode *ri;
4521da177e4SLinus Torvalds 	struct jffs2_raw_dirent *rd;
4531da177e4SLinus Torvalds 	struct jffs2_full_dnode *fn;
4541da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
4551da177e4SLinus Torvalds 	int namelen;
4569fe4854cSDavid Woodhouse 	uint32_t alloclen;
4571da177e4SLinus Torvalds 	int ret;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	mode |= S_IFDIR;
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	ri = jffs2_alloc_raw_inode();
4621da177e4SLinus Torvalds 	if (!ri)
4631da177e4SLinus Torvalds 		return -ENOMEM;
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	c = JFFS2_SB_INFO(dir_i->i_sb);
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds 	/* Try to reserve enough space for both node and dirent.
4681da177e4SLinus Torvalds 	 * Just the node will do for now, though
4691da177e4SLinus Torvalds 	 */
4701da177e4SLinus Torvalds 	namelen = dentry->d_name.len;
4719fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
472e631ddbaSFerenc Havasi 				  JFFS2_SUMMARY_INODE_SIZE);
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	if (ret) {
4751da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
4761da177e4SLinus Torvalds 		return ret;
4771da177e4SLinus Torvalds 	}
4781da177e4SLinus Torvalds 
479cfc8dc6fSKaiGai Kohei 	inode = jffs2_new_inode(dir_i, mode, ri);
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	if (IS_ERR(inode)) {
4821da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
4831da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
4841da177e4SLinus Torvalds 		return PTR_ERR(inode);
4851da177e4SLinus Torvalds 	}
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	inode->i_op = &jffs2_dir_inode_operations;
4881da177e4SLinus Torvalds 	inode->i_fop = &jffs2_dir_operations;
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	f = JFFS2_INODE_INFO(inode);
4911da177e4SLinus Torvalds 
49227c72b04SDavid Woodhouse 	/* Directories get nlink 2 at start */
493bfe86848SMiklos Szeredi 	set_nlink(inode, 2);
49427c72b04SDavid Woodhouse 	/* but ic->pino_nlink is the parent ino# */
49527c72b04SDavid Woodhouse 	f->inocache->pino_nlink = dir_i->i_ino;
49627c72b04SDavid Woodhouse 
4971da177e4SLinus Torvalds 	ri->data_crc = cpu_to_je32(0);
4981da177e4SLinus Torvalds 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
4991da177e4SLinus Torvalds 
5009fe4854cSDavid Woodhouse 	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	jffs2_free_raw_inode(ri);
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 	if (IS_ERR(fn)) {
5051da177e4SLinus Torvalds 		/* Eeek. Wave bye bye */
506ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
5071da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
508f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fn);
509f324e4cbSDavid Woodhouse 		goto fail;
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 	/* No data here. Only a metadata node, which will be
5121da177e4SLinus Torvalds 	   obsoleted by the first data write
5131da177e4SLinus Torvalds 	*/
5141da177e4SLinus Torvalds 	f->metadata = fn;
515ced22070SDavid Woodhouse 	mutex_unlock(&f->sem);
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
518aa98d7cfSKaiGai Kohei 
5192a7dba39SEric Paris 	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
520f324e4cbSDavid Woodhouse 	if (ret)
521f324e4cbSDavid Woodhouse 		goto fail;
522f324e4cbSDavid Woodhouse 
523cfc8dc6fSKaiGai Kohei 	ret = jffs2_init_acl_post(inode);
524f324e4cbSDavid Woodhouse 	if (ret)
525f324e4cbSDavid Woodhouse 		goto fail;
526aa98d7cfSKaiGai Kohei 
5279fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
528e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
529f324e4cbSDavid Woodhouse 	if (ret)
530f324e4cbSDavid Woodhouse 		goto fail;
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	rd = jffs2_alloc_raw_dirent();
5331da177e4SLinus Torvalds 	if (!rd) {
5341da177e4SLinus Torvalds 		/* Argh. Now we treat it like a normal delete */
5351da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
536f324e4cbSDavid Woodhouse 		ret = -ENOMEM;
537f324e4cbSDavid Woodhouse 		goto fail;
5381da177e4SLinus Torvalds 	}
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
541ced22070SDavid Woodhouse 	mutex_lock(&dir_f->sem);
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
5441da177e4SLinus Torvalds 	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
5451da177e4SLinus Torvalds 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
5461da177e4SLinus Torvalds 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	rd->pino = cpu_to_je32(dir_i->i_ino);
5491da177e4SLinus Torvalds 	rd->version = cpu_to_je32(++dir_f->highest_version);
5501da177e4SLinus Torvalds 	rd->ino = cpu_to_je32(inode->i_ino);
5511da177e4SLinus Torvalds 	rd->mctime = cpu_to_je32(get_seconds());
5521da177e4SLinus Torvalds 	rd->nsize = namelen;
5531da177e4SLinus Torvalds 	rd->type = DT_DIR;
5541da177e4SLinus Torvalds 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
5551da177e4SLinus Torvalds 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
5561da177e4SLinus Torvalds 
5579fe4854cSDavid Woodhouse 	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	if (IS_ERR(fd)) {
5601da177e4SLinus Torvalds 		/* dirent failed to write. Delete the inode normally
5611da177e4SLinus Torvalds 		   as if it were the final unlink() */
5621da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
5631da177e4SLinus Torvalds 		jffs2_free_raw_dirent(rd);
564ced22070SDavid Woodhouse 		mutex_unlock(&dir_f->sem);
565f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fd);
566f324e4cbSDavid Woodhouse 		goto fail;
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
570d8c76e6fSDave Hansen 	inc_nlink(dir_i);
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	jffs2_free_raw_dirent(rd);
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	/* Link the fd into the inode's list, obsoleting an old
5751da177e4SLinus Torvalds 	   one if necessary. */
5761da177e4SLinus Torvalds 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
5771da177e4SLinus Torvalds 
578ced22070SDavid Woodhouse 	mutex_unlock(&dir_f->sem);
5791da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
5801da177e4SLinus Torvalds 
581e72e6497SDavid Woodhouse 	unlock_new_inode(inode);
5828fc37ec5SAl Viro 	d_instantiate(dentry, inode);
5831da177e4SLinus Torvalds 	return 0;
584f324e4cbSDavid Woodhouse 
585f324e4cbSDavid Woodhouse  fail:
58641cce647SAl Viro 	iget_failed(inode);
587f324e4cbSDavid Woodhouse 	return ret;
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
5911da177e4SLinus Torvalds {
59227c72b04SDavid Woodhouse 	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
59327c72b04SDavid Woodhouse 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
5942b0143b5SDavid Howells 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
5951da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
5961da177e4SLinus Torvalds 	int ret;
59727c72b04SDavid Woodhouse 	uint32_t now = get_seconds();
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 	for (fd = f->dents ; fd; fd = fd->next) {
6001da177e4SLinus Torvalds 		if (fd->ino)
6011da177e4SLinus Torvalds 			return -ENOTEMPTY;
6021da177e4SLinus Torvalds 	}
60327c72b04SDavid Woodhouse 
60427c72b04SDavid Woodhouse 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
60527c72b04SDavid Woodhouse 			      dentry->d_name.len, f, now);
60627c72b04SDavid Woodhouse 	if (!ret) {
60727c72b04SDavid Woodhouse 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
6082b0143b5SDavid Howells 		clear_nlink(d_inode(dentry));
6099a53c3a7SDave Hansen 		drop_nlink(dir_i);
61027c72b04SDavid Woodhouse 	}
6111da177e4SLinus Torvalds 	return ret;
6121da177e4SLinus Torvalds }
6131da177e4SLinus Torvalds 
6141a67aafbSAl Viro static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev)
6151da177e4SLinus Torvalds {
6161da177e4SLinus Torvalds 	struct jffs2_inode_info *f, *dir_f;
6171da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
6181da177e4SLinus Torvalds 	struct inode *inode;
6191da177e4SLinus Torvalds 	struct jffs2_raw_inode *ri;
6201da177e4SLinus Torvalds 	struct jffs2_raw_dirent *rd;
6211da177e4SLinus Torvalds 	struct jffs2_full_dnode *fn;
6221da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
6231da177e4SLinus Torvalds 	int namelen;
624aef9ab47SDavid Woodhouse 	union jffs2_device_node dev;
6251da177e4SLinus Torvalds 	int devlen = 0;
6269fe4854cSDavid Woodhouse 	uint32_t alloclen;
6271da177e4SLinus Torvalds 	int ret;
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	ri = jffs2_alloc_raw_inode();
6301da177e4SLinus Torvalds 	if (!ri)
6311da177e4SLinus Torvalds 		return -ENOMEM;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	c = JFFS2_SB_INFO(dir_i->i_sb);
6341da177e4SLinus Torvalds 
635aef9ab47SDavid Woodhouse 	if (S_ISBLK(mode) || S_ISCHR(mode))
636aef9ab47SDavid Woodhouse 		devlen = jffs2_encode_dev(&dev, rdev);
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	/* Try to reserve enough space for both node and dirent.
6391da177e4SLinus Torvalds 	 * Just the node will do for now, though
6401da177e4SLinus Torvalds 	 */
6411da177e4SLinus Torvalds 	namelen = dentry->d_name.len;
6429fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
643e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	if (ret) {
6461da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
6471da177e4SLinus Torvalds 		return ret;
6481da177e4SLinus Torvalds 	}
6491da177e4SLinus Torvalds 
650cfc8dc6fSKaiGai Kohei 	inode = jffs2_new_inode(dir_i, mode, ri);
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	if (IS_ERR(inode)) {
6531da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
6541da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
6551da177e4SLinus Torvalds 		return PTR_ERR(inode);
6561da177e4SLinus Torvalds 	}
6571da177e4SLinus Torvalds 	inode->i_op = &jffs2_file_inode_operations;
6581da177e4SLinus Torvalds 	init_special_inode(inode, inode->i_mode, rdev);
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	f = JFFS2_INODE_INFO(inode);
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	ri->dsize = ri->csize = cpu_to_je32(devlen);
6631da177e4SLinus Torvalds 	ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
6641da177e4SLinus Torvalds 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	ri->compr = JFFS2_COMPR_NONE;
6671da177e4SLinus Torvalds 	ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
6681da177e4SLinus Torvalds 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
6691da177e4SLinus Torvalds 
6709fe4854cSDavid Woodhouse 	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	jffs2_free_raw_inode(ri);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	if (IS_ERR(fn)) {
6751da177e4SLinus Torvalds 		/* Eeek. Wave bye bye */
676ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
6771da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
678f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fn);
679f324e4cbSDavid Woodhouse 		goto fail;
6801da177e4SLinus Torvalds 	}
6811da177e4SLinus Torvalds 	/* No data here. Only a metadata node, which will be
6821da177e4SLinus Torvalds 	   obsoleted by the first data write
6831da177e4SLinus Torvalds 	*/
6841da177e4SLinus Torvalds 	f->metadata = fn;
685ced22070SDavid Woodhouse 	mutex_unlock(&f->sem);
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
688aa98d7cfSKaiGai Kohei 
6892a7dba39SEric Paris 	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
690f324e4cbSDavid Woodhouse 	if (ret)
691f324e4cbSDavid Woodhouse 		goto fail;
692f324e4cbSDavid Woodhouse 
693cfc8dc6fSKaiGai Kohei 	ret = jffs2_init_acl_post(inode);
694f324e4cbSDavid Woodhouse 	if (ret)
695f324e4cbSDavid Woodhouse 		goto fail;
696aa98d7cfSKaiGai Kohei 
6979fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
698e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
699f324e4cbSDavid Woodhouse 	if (ret)
700f324e4cbSDavid Woodhouse 		goto fail;
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds 	rd = jffs2_alloc_raw_dirent();
7031da177e4SLinus Torvalds 	if (!rd) {
7041da177e4SLinus Torvalds 		/* Argh. Now we treat it like a normal delete */
7051da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
706f324e4cbSDavid Woodhouse 		ret = -ENOMEM;
707f324e4cbSDavid Woodhouse 		goto fail;
7081da177e4SLinus Torvalds 	}
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
711ced22070SDavid Woodhouse 	mutex_lock(&dir_f->sem);
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
7141da177e4SLinus Torvalds 	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
7151da177e4SLinus Torvalds 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
7161da177e4SLinus Torvalds 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	rd->pino = cpu_to_je32(dir_i->i_ino);
7191da177e4SLinus Torvalds 	rd->version = cpu_to_je32(++dir_f->highest_version);
7201da177e4SLinus Torvalds 	rd->ino = cpu_to_je32(inode->i_ino);
7211da177e4SLinus Torvalds 	rd->mctime = cpu_to_je32(get_seconds());
7221da177e4SLinus Torvalds 	rd->nsize = namelen;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	/* XXX: This is ugly. */
7251da177e4SLinus Torvalds 	rd->type = (mode & S_IFMT) >> 12;
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
7281da177e4SLinus Torvalds 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
7291da177e4SLinus Torvalds 
7309fe4854cSDavid Woodhouse 	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	if (IS_ERR(fd)) {
7331da177e4SLinus Torvalds 		/* dirent failed to write. Delete the inode normally
7341da177e4SLinus Torvalds 		   as if it were the final unlink() */
7351da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
7361da177e4SLinus Torvalds 		jffs2_free_raw_dirent(rd);
737ced22070SDavid Woodhouse 		mutex_unlock(&dir_f->sem);
738f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fd);
739f324e4cbSDavid Woodhouse 		goto fail;
7401da177e4SLinus Torvalds 	}
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	jffs2_free_raw_dirent(rd);
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	/* Link the fd into the inode's list, obsoleting an old
7471da177e4SLinus Torvalds 	   one if necessary. */
7481da177e4SLinus Torvalds 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
7491da177e4SLinus Torvalds 
750ced22070SDavid Woodhouse 	mutex_unlock(&dir_f->sem);
7511da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
7521da177e4SLinus Torvalds 
753e72e6497SDavid Woodhouse 	unlock_new_inode(inode);
7548fc37ec5SAl Viro 	d_instantiate(dentry, inode);
7551da177e4SLinus Torvalds 	return 0;
756f324e4cbSDavid Woodhouse 
757f324e4cbSDavid Woodhouse  fail:
75841cce647SAl Viro 	iget_failed(inode);
759f324e4cbSDavid Woodhouse 	return ret;
7601da177e4SLinus Torvalds }
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
763f03b8ad8SMiklos Szeredi 			 struct inode *new_dir_i, struct dentry *new_dentry,
764f03b8ad8SMiklos Szeredi 			 unsigned int flags)
7651da177e4SLinus Torvalds {
7661da177e4SLinus Torvalds 	int ret;
7671da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
7681da177e4SLinus Torvalds 	struct jffs2_inode_info *victim_f = NULL;
7691da177e4SLinus Torvalds 	uint8_t type;
7703a69e0cdSArtem B. Bityutskiy 	uint32_t now;
7711da177e4SLinus Torvalds 
772f03b8ad8SMiklos Szeredi 	if (flags & ~RENAME_NOREPLACE)
773f03b8ad8SMiklos Szeredi 		return -EINVAL;
774f03b8ad8SMiklos Szeredi 
7751da177e4SLinus Torvalds 	/* The VFS will check for us and prevent trying to rename a
7761da177e4SLinus Torvalds 	 * file over a directory and vice versa, but if it's a directory,
7771da177e4SLinus Torvalds 	 * the VFS can't check whether the victim is empty. The filesystem
7781da177e4SLinus Torvalds 	 * needs to do that for itself.
7791da177e4SLinus Torvalds 	 */
7802b0143b5SDavid Howells 	if (d_really_is_positive(new_dentry)) {
7812b0143b5SDavid Howells 		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
782e36cb0b8SDavid Howells 		if (d_is_dir(new_dentry)) {
7831da177e4SLinus Torvalds 			struct jffs2_full_dirent *fd;
7841da177e4SLinus Torvalds 
785ced22070SDavid Woodhouse 			mutex_lock(&victim_f->sem);
7861da177e4SLinus Torvalds 			for (fd = victim_f->dents; fd; fd = fd->next) {
7871da177e4SLinus Torvalds 				if (fd->ino) {
788ced22070SDavid Woodhouse 					mutex_unlock(&victim_f->sem);
7891da177e4SLinus Torvalds 					return -ENOTEMPTY;
7901da177e4SLinus Torvalds 				}
7911da177e4SLinus Torvalds 			}
792ced22070SDavid Woodhouse 			mutex_unlock(&victim_f->sem);
7931da177e4SLinus Torvalds 		}
7941da177e4SLinus Torvalds 	}
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	/* XXX: We probably ought to alloc enough space for
7971da177e4SLinus Torvalds 	   both nodes at the same time. Writing the new link,
7981da177e4SLinus Torvalds 	   then getting -ENOSPC, is quite bad :)
7991da177e4SLinus Torvalds 	*/
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 	/* Make a hard link */
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 	/* XXX: This is ugly */
8042b0143b5SDavid Howells 	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
8051da177e4SLinus Torvalds 	if (!type) type = DT_REG;
8061da177e4SLinus Torvalds 
8073a69e0cdSArtem B. Bityutskiy 	now = get_seconds();
8081da177e4SLinus Torvalds 	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
8092b0143b5SDavid Howells 			    d_inode(old_dentry)->i_ino, type,
8103a69e0cdSArtem B. Bityutskiy 			    new_dentry->d_name.name, new_dentry->d_name.len, now);
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 	if (ret)
8131da177e4SLinus Torvalds 		return ret;
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	if (victim_f) {
8161da177e4SLinus Torvalds 		/* There was a victim. Kill it off nicely */
817e36cb0b8SDavid Howells 		if (d_is_dir(new_dentry))
8182b0143b5SDavid Howells 			clear_nlink(d_inode(new_dentry));
81922ba747fSAl Viro 		else
8202b0143b5SDavid Howells 			drop_nlink(d_inode(new_dentry));
8211da177e4SLinus Torvalds 		/* Don't oops if the victim was a dirent pointing to an
8221da177e4SLinus Torvalds 		   inode which didn't exist. */
8231da177e4SLinus Torvalds 		if (victim_f->inocache) {
824ced22070SDavid Woodhouse 			mutex_lock(&victim_f->sem);
825e36cb0b8SDavid Howells 			if (d_is_dir(new_dentry))
82627c72b04SDavid Woodhouse 				victim_f->inocache->pino_nlink = 0;
82727c72b04SDavid Woodhouse 			else
82827c72b04SDavid Woodhouse 				victim_f->inocache->pino_nlink--;
829ced22070SDavid Woodhouse 			mutex_unlock(&victim_f->sem);
8301da177e4SLinus Torvalds 		}
8311da177e4SLinus Torvalds 	}
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	/* If it was a directory we moved, and there was no victim,
8341da177e4SLinus Torvalds 	   increase i_nlink on its new parent */
835e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry) && !victim_f)
836d8c76e6fSDave Hansen 		inc_nlink(new_dir_i);
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	/* Unlink the original */
8391da177e4SLinus Torvalds 	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
8403a69e0cdSArtem B. Bityutskiy 			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	/* We don't touch inode->i_nlink */
8431da177e4SLinus Torvalds 
8441da177e4SLinus Torvalds 	if (ret) {
8451da177e4SLinus Torvalds 		/* Oh shit. We really ought to make a single node which can do both atomically */
8462b0143b5SDavid Howells 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
847ced22070SDavid Woodhouse 		mutex_lock(&f->sem);
8482b0143b5SDavid Howells 		inc_nlink(d_inode(old_dentry));
849e36cb0b8SDavid Howells 		if (f->inocache && !d_is_dir(old_dentry))
85027c72b04SDavid Woodhouse 			f->inocache->pino_nlink++;
851ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
8521da177e4SLinus Torvalds 
853da320f05SJoe Perches 		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
854da320f05SJoe Perches 			  __func__, ret);
855f9381284SAl Viro 		/*
856f9381284SAl Viro 		 * We can't keep the target in dcache after that.
857f9381284SAl Viro 		 * For one thing, we can't afford dentry aliases for directories.
858f9381284SAl Viro 		 * For another, if there was a victim, we _can't_ set new inode
859f9381284SAl Viro 		 * for that sucker and we have to trigger mount eviction - the
860f9381284SAl Viro 		 * caller won't do it on its own since we are returning an error.
861f9381284SAl Viro 		 */
862f9381284SAl Viro 		d_invalidate(new_dentry);
8633a69e0cdSArtem B. Bityutskiy 		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
8641da177e4SLinus Torvalds 		return ret;
8651da177e4SLinus Torvalds 	}
8661da177e4SLinus Torvalds 
867e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry))
8689a53c3a7SDave Hansen 		drop_nlink(old_dir_i);
8691da177e4SLinus Torvalds 
8703a69e0cdSArtem B. Bityutskiy 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
8713a69e0cdSArtem B. Bityutskiy 
8721da177e4SLinus Torvalds 	return 0;
8731da177e4SLinus Torvalds }
8741da177e4SLinus Torvalds 
875