xref: /openbmc/linux/fs/jffs2/dir.c (revision cac2f8b8)
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 
27549c7297SChristian Brauner static int jffs2_create (struct user_namespace *, struct inode *,
28549c7297SChristian Brauner 		         struct dentry *, umode_t, 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 *);
33549c7297SChristian Brauner static int jffs2_symlink (struct user_namespace *, struct inode *,
34549c7297SChristian Brauner 			  struct dentry *, const char *);
35549c7297SChristian Brauner static int jffs2_mkdir (struct user_namespace *, struct inode *,struct dentry *,
36549c7297SChristian Brauner 			umode_t);
371da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *,struct dentry *);
38549c7297SChristian Brauner static int jffs2_mknod (struct user_namespace *, struct inode *,struct dentry *,
39549c7297SChristian Brauner 			umode_t,dev_t);
40549c7297SChristian Brauner static int jffs2_rename (struct user_namespace *, struct inode *,
41549c7297SChristian Brauner 			 struct dentry *, struct inode *, struct dentry *,
42f03b8ad8SMiklos Szeredi 			 unsigned int);
431da177e4SLinus Torvalds 
444b6f5d20SArjan van de Ven const struct file_operations jffs2_dir_operations =
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds 	.read =		generic_read_dir,
47c51da20cSAl Viro 	.iterate_shared=jffs2_readdir,
480533400bSStoyan Gaydarov 	.unlocked_ioctl=jffs2_ioctl,
493222a3e5SChristoph Hellwig 	.fsync =	jffs2_fsync,
503222a3e5SChristoph Hellwig 	.llseek =	generic_file_llseek,
511da177e4SLinus Torvalds };
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 
5492e1d5beSArjan van de Ven const struct inode_operations jffs2_dir_inode_operations =
551da177e4SLinus Torvalds {
56265489f0SDavid Woodhouse 	.create =	jffs2_create,
57265489f0SDavid Woodhouse 	.lookup =	jffs2_lookup,
581da177e4SLinus Torvalds 	.link =		jffs2_link,
591da177e4SLinus Torvalds 	.unlink =	jffs2_unlink,
601da177e4SLinus Torvalds 	.symlink =	jffs2_symlink,
611da177e4SLinus Torvalds 	.mkdir =	jffs2_mkdir,
621da177e4SLinus Torvalds 	.rmdir =	jffs2_rmdir,
631da177e4SLinus Torvalds 	.mknod =	jffs2_mknod,
641da177e4SLinus Torvalds 	.rename =	jffs2_rename,
65*cac2f8b8SChristian Brauner 	.get_inode_acl =	jffs2_get_acl,
66f2963d45SChristoph Hellwig 	.set_acl =	jffs2_set_acl,
671da177e4SLinus Torvalds 	.setattr =	jffs2_setattr,
68aa98d7cfSKaiGai Kohei 	.listxattr =	jffs2_listxattr,
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 
163549c7297SChristian Brauner static int jffs2_create(struct user_namespace *mnt_userns, struct inode *dir_i,
164549c7297SChristian Brauner 			struct dentry *dentry, 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 
207c4592b9cSArnd Bergmann 	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 
2151e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
2161da177e4SLinus Torvalds 	return 0;
217aa98d7cfSKaiGai Kohei 
218aa98d7cfSKaiGai Kohei  fail:
21941cce647SAl Viro 	iget_failed(inode);
220aa98d7cfSKaiGai Kohei 	jffs2_free_raw_inode(ri);
221aa98d7cfSKaiGai Kohei 	return ret;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds /***********************************************************************/
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
2301da177e4SLinus Torvalds 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2312b0143b5SDavid Howells 	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry));
2321da177e4SLinus Torvalds 	int ret;
233c4592b9cSArnd Bergmann 	uint32_t now = JFFS2_NOW();
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
2363a69e0cdSArtem B. Bityutskiy 			      dentry->d_name.len, dead_f, now);
2371da177e4SLinus Torvalds 	if (dead_f->inocache)
2382b0143b5SDavid Howells 		set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink);
2393a69e0cdSArtem B. Bityutskiy 	if (!ret)
240c4592b9cSArnd Bergmann 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2411da177e4SLinus Torvalds 	return ret;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds /***********************************************************************/
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
2471da177e4SLinus Torvalds {
248fc64005cSAl Viro 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb);
2492b0143b5SDavid Howells 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
2501da177e4SLinus Torvalds 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2511da177e4SLinus Torvalds 	int ret;
2521da177e4SLinus Torvalds 	uint8_t type;
2533a69e0cdSArtem B. Bityutskiy 	uint32_t now;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	/* Don't let people make hard links to bad inodes. */
2561da177e4SLinus Torvalds 	if (!f->inocache)
2571da177e4SLinus Torvalds 		return -EIO;
2581da177e4SLinus Torvalds 
259e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry))
2601da177e4SLinus Torvalds 		return -EPERM;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	/* XXX: This is ugly */
2632b0143b5SDavid Howells 	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
2641da177e4SLinus Torvalds 	if (!type) type = DT_REG;
2651da177e4SLinus Torvalds 
266c4592b9cSArnd Bergmann 	now = JFFS2_NOW();
2673a69e0cdSArtem B. Bityutskiy 	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	if (!ret) {
270ced22070SDavid Woodhouse 		mutex_lock(&f->sem);
2712b0143b5SDavid Howells 		set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink);
272ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
2732b0143b5SDavid Howells 		d_instantiate(dentry, d_inode(old_dentry));
274c4592b9cSArnd Bergmann 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2752b0143b5SDavid Howells 		ihold(d_inode(old_dentry));
2761da177e4SLinus Torvalds 	}
2771da177e4SLinus Torvalds 	return ret;
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds /***********************************************************************/
2811da177e4SLinus Torvalds 
282549c7297SChristian Brauner static int jffs2_symlink (struct user_namespace *mnt_userns, struct inode *dir_i,
283549c7297SChristian Brauner 			  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);
407c4592b9cSArnd Bergmann 	rd->mctime = cpu_to_je32(JFFS2_NOW());
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 
425c4592b9cSArnd Bergmann 	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 
4361e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
4371da177e4SLinus Torvalds 	return 0;
438f324e4cbSDavid Woodhouse 
439f324e4cbSDavid Woodhouse  fail:
44041cce647SAl Viro 	iget_failed(inode);
441f324e4cbSDavid Woodhouse 	return ret;
4421da177e4SLinus Torvalds }
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 
445549c7297SChristian Brauner static int jffs2_mkdir (struct user_namespace *mnt_userns, struct inode *dir_i,
446549c7297SChristian Brauner 		        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);
551c4592b9cSArnd Bergmann 	rd->mctime = cpu_to_je32(JFFS2_NOW());
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 
569c4592b9cSArnd Bergmann 	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 
5811e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
5821da177e4SLinus Torvalds 	return 0;
583f324e4cbSDavid Woodhouse 
584f324e4cbSDavid Woodhouse  fail:
58541cce647SAl Viro 	iget_failed(inode);
586f324e4cbSDavid Woodhouse 	return ret;
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
5901da177e4SLinus Torvalds {
59127c72b04SDavid Woodhouse 	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
59227c72b04SDavid Woodhouse 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
5932b0143b5SDavid Howells 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
5941da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
5951da177e4SLinus Torvalds 	int ret;
596c4592b9cSArnd Bergmann 	uint32_t now = JFFS2_NOW();
5971da177e4SLinus Torvalds 
598798b7347SZhe Li 	mutex_lock(&f->sem);
5991da177e4SLinus Torvalds 	for (fd = f->dents ; fd; fd = fd->next) {
600798b7347SZhe Li 		if (fd->ino) {
601798b7347SZhe Li 			mutex_unlock(&f->sem);
6021da177e4SLinus Torvalds 			return -ENOTEMPTY;
6031da177e4SLinus Torvalds 		}
604798b7347SZhe Li 	}
605798b7347SZhe Li 	mutex_unlock(&f->sem);
60627c72b04SDavid Woodhouse 
60727c72b04SDavid Woodhouse 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
60827c72b04SDavid Woodhouse 			      dentry->d_name.len, f, now);
60927c72b04SDavid Woodhouse 	if (!ret) {
610c4592b9cSArnd Bergmann 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
6112b0143b5SDavid Howells 		clear_nlink(d_inode(dentry));
6129a53c3a7SDave Hansen 		drop_nlink(dir_i);
61327c72b04SDavid Woodhouse 	}
6141da177e4SLinus Torvalds 	return ret;
6151da177e4SLinus Torvalds }
6161da177e4SLinus Torvalds 
617549c7297SChristian Brauner static int jffs2_mknod (struct user_namespace *mnt_userns, struct inode *dir_i,
618549c7297SChristian Brauner 		        struct dentry *dentry, umode_t mode, dev_t rdev)
6191da177e4SLinus Torvalds {
6201da177e4SLinus Torvalds 	struct jffs2_inode_info *f, *dir_f;
6211da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
6221da177e4SLinus Torvalds 	struct inode *inode;
6231da177e4SLinus Torvalds 	struct jffs2_raw_inode *ri;
6241da177e4SLinus Torvalds 	struct jffs2_raw_dirent *rd;
6251da177e4SLinus Torvalds 	struct jffs2_full_dnode *fn;
6261da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
6271da177e4SLinus Torvalds 	int namelen;
628aef9ab47SDavid Woodhouse 	union jffs2_device_node dev;
6291da177e4SLinus Torvalds 	int devlen = 0;
6309fe4854cSDavid Woodhouse 	uint32_t alloclen;
6311da177e4SLinus Torvalds 	int ret;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	ri = jffs2_alloc_raw_inode();
6341da177e4SLinus Torvalds 	if (!ri)
6351da177e4SLinus Torvalds 		return -ENOMEM;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	c = JFFS2_SB_INFO(dir_i->i_sb);
6381da177e4SLinus Torvalds 
639aef9ab47SDavid Woodhouse 	if (S_ISBLK(mode) || S_ISCHR(mode))
640aef9ab47SDavid Woodhouse 		devlen = jffs2_encode_dev(&dev, rdev);
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds 	/* Try to reserve enough space for both node and dirent.
6431da177e4SLinus Torvalds 	 * Just the node will do for now, though
6441da177e4SLinus Torvalds 	 */
6451da177e4SLinus Torvalds 	namelen = dentry->d_name.len;
6469fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
647e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 	if (ret) {
6501da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
6511da177e4SLinus Torvalds 		return ret;
6521da177e4SLinus Torvalds 	}
6531da177e4SLinus Torvalds 
654cfc8dc6fSKaiGai Kohei 	inode = jffs2_new_inode(dir_i, mode, ri);
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 	if (IS_ERR(inode)) {
6571da177e4SLinus Torvalds 		jffs2_free_raw_inode(ri);
6581da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
6591da177e4SLinus Torvalds 		return PTR_ERR(inode);
6601da177e4SLinus Torvalds 	}
6611da177e4SLinus Torvalds 	inode->i_op = &jffs2_file_inode_operations;
6621da177e4SLinus Torvalds 	init_special_inode(inode, inode->i_mode, rdev);
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	f = JFFS2_INODE_INFO(inode);
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	ri->dsize = ri->csize = cpu_to_je32(devlen);
6671da177e4SLinus Torvalds 	ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
6681da177e4SLinus Torvalds 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	ri->compr = JFFS2_COMPR_NONE;
6711da177e4SLinus Torvalds 	ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
6721da177e4SLinus Torvalds 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
6731da177e4SLinus Torvalds 
6749fe4854cSDavid Woodhouse 	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	jffs2_free_raw_inode(ri);
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	if (IS_ERR(fn)) {
6791da177e4SLinus Torvalds 		/* Eeek. Wave bye bye */
680ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
6811da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
682f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fn);
683f324e4cbSDavid Woodhouse 		goto fail;
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 	/* No data here. Only a metadata node, which will be
6861da177e4SLinus Torvalds 	   obsoleted by the first data write
6871da177e4SLinus Torvalds 	*/
6881da177e4SLinus Torvalds 	f->metadata = fn;
689ced22070SDavid Woodhouse 	mutex_unlock(&f->sem);
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
692aa98d7cfSKaiGai Kohei 
6932a7dba39SEric Paris 	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
694f324e4cbSDavid Woodhouse 	if (ret)
695f324e4cbSDavid Woodhouse 		goto fail;
696f324e4cbSDavid Woodhouse 
697cfc8dc6fSKaiGai Kohei 	ret = jffs2_init_acl_post(inode);
698f324e4cbSDavid Woodhouse 	if (ret)
699f324e4cbSDavid Woodhouse 		goto fail;
700aa98d7cfSKaiGai Kohei 
7019fe4854cSDavid Woodhouse 	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
702e631ddbaSFerenc Havasi 				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
703f324e4cbSDavid Woodhouse 	if (ret)
704f324e4cbSDavid Woodhouse 		goto fail;
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds 	rd = jffs2_alloc_raw_dirent();
7071da177e4SLinus Torvalds 	if (!rd) {
7081da177e4SLinus Torvalds 		/* Argh. Now we treat it like a normal delete */
7091da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
710f324e4cbSDavid Woodhouse 		ret = -ENOMEM;
711f324e4cbSDavid Woodhouse 		goto fail;
7121da177e4SLinus Torvalds 	}
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	dir_f = JFFS2_INODE_INFO(dir_i);
715ced22070SDavid Woodhouse 	mutex_lock(&dir_f->sem);
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
7181da177e4SLinus Torvalds 	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
7191da177e4SLinus Torvalds 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
7201da177e4SLinus Torvalds 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	rd->pino = cpu_to_je32(dir_i->i_ino);
7231da177e4SLinus Torvalds 	rd->version = cpu_to_je32(++dir_f->highest_version);
7241da177e4SLinus Torvalds 	rd->ino = cpu_to_je32(inode->i_ino);
725c4592b9cSArnd Bergmann 	rd->mctime = cpu_to_je32(JFFS2_NOW());
7261da177e4SLinus Torvalds 	rd->nsize = namelen;
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	/* XXX: This is ugly. */
7291da177e4SLinus Torvalds 	rd->type = (mode & S_IFMT) >> 12;
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
7321da177e4SLinus Torvalds 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
7331da177e4SLinus Torvalds 
7349fe4854cSDavid Woodhouse 	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 	if (IS_ERR(fd)) {
7371da177e4SLinus Torvalds 		/* dirent failed to write. Delete the inode normally
7381da177e4SLinus Torvalds 		   as if it were the final unlink() */
7391da177e4SLinus Torvalds 		jffs2_complete_reservation(c);
7401da177e4SLinus Torvalds 		jffs2_free_raw_dirent(rd);
741ced22070SDavid Woodhouse 		mutex_unlock(&dir_f->sem);
742f324e4cbSDavid Woodhouse 		ret = PTR_ERR(fd);
743f324e4cbSDavid Woodhouse 		goto fail;
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 
746c4592b9cSArnd Bergmann 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	jffs2_free_raw_dirent(rd);
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds 	/* Link the fd into the inode's list, obsoleting an old
7511da177e4SLinus Torvalds 	   one if necessary. */
7521da177e4SLinus Torvalds 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
7531da177e4SLinus Torvalds 
754ced22070SDavid Woodhouse 	mutex_unlock(&dir_f->sem);
7551da177e4SLinus Torvalds 	jffs2_complete_reservation(c);
7561da177e4SLinus Torvalds 
7571e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
7581da177e4SLinus Torvalds 	return 0;
759f324e4cbSDavid Woodhouse 
760f324e4cbSDavid Woodhouse  fail:
76141cce647SAl Viro 	iget_failed(inode);
762f324e4cbSDavid Woodhouse 	return ret;
7631da177e4SLinus Torvalds }
7641da177e4SLinus Torvalds 
765549c7297SChristian Brauner static int jffs2_rename (struct user_namespace *mnt_userns,
766549c7297SChristian Brauner 			 struct inode *old_dir_i, struct dentry *old_dentry,
767f03b8ad8SMiklos Szeredi 			 struct inode *new_dir_i, struct dentry *new_dentry,
768f03b8ad8SMiklos Szeredi 			 unsigned int flags)
7691da177e4SLinus Torvalds {
7701da177e4SLinus Torvalds 	int ret;
7711da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
7721da177e4SLinus Torvalds 	struct jffs2_inode_info *victim_f = NULL;
7731da177e4SLinus Torvalds 	uint8_t type;
7743a69e0cdSArtem B. Bityutskiy 	uint32_t now;
7751da177e4SLinus Torvalds 
776f03b8ad8SMiklos Szeredi 	if (flags & ~RENAME_NOREPLACE)
777f03b8ad8SMiklos Szeredi 		return -EINVAL;
778f03b8ad8SMiklos Szeredi 
7791da177e4SLinus Torvalds 	/* The VFS will check for us and prevent trying to rename a
7801da177e4SLinus Torvalds 	 * file over a directory and vice versa, but if it's a directory,
7811da177e4SLinus Torvalds 	 * the VFS can't check whether the victim is empty. The filesystem
7821da177e4SLinus Torvalds 	 * needs to do that for itself.
7831da177e4SLinus Torvalds 	 */
7842b0143b5SDavid Howells 	if (d_really_is_positive(new_dentry)) {
7852b0143b5SDavid Howells 		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
786e36cb0b8SDavid Howells 		if (d_is_dir(new_dentry)) {
7871da177e4SLinus Torvalds 			struct jffs2_full_dirent *fd;
7881da177e4SLinus Torvalds 
789ced22070SDavid Woodhouse 			mutex_lock(&victim_f->sem);
7901da177e4SLinus Torvalds 			for (fd = victim_f->dents; fd; fd = fd->next) {
7911da177e4SLinus Torvalds 				if (fd->ino) {
792ced22070SDavid Woodhouse 					mutex_unlock(&victim_f->sem);
7931da177e4SLinus Torvalds 					return -ENOTEMPTY;
7941da177e4SLinus Torvalds 				}
7951da177e4SLinus Torvalds 			}
796ced22070SDavid Woodhouse 			mutex_unlock(&victim_f->sem);
7971da177e4SLinus Torvalds 		}
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 	/* XXX: We probably ought to alloc enough space for
8011da177e4SLinus Torvalds 	   both nodes at the same time. Writing the new link,
8021da177e4SLinus Torvalds 	   then getting -ENOSPC, is quite bad :)
8031da177e4SLinus Torvalds 	*/
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 	/* Make a hard link */
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 	/* XXX: This is ugly */
8082b0143b5SDavid Howells 	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
8091da177e4SLinus Torvalds 	if (!type) type = DT_REG;
8101da177e4SLinus Torvalds 
811c4592b9cSArnd Bergmann 	now = JFFS2_NOW();
8121da177e4SLinus Torvalds 	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
8132b0143b5SDavid Howells 			    d_inode(old_dentry)->i_ino, type,
8143a69e0cdSArtem B. Bityutskiy 			    new_dentry->d_name.name, new_dentry->d_name.len, now);
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds 	if (ret)
8171da177e4SLinus Torvalds 		return ret;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	if (victim_f) {
8201da177e4SLinus Torvalds 		/* There was a victim. Kill it off nicely */
821e36cb0b8SDavid Howells 		if (d_is_dir(new_dentry))
8222b0143b5SDavid Howells 			clear_nlink(d_inode(new_dentry));
82322ba747fSAl Viro 		else
8242b0143b5SDavid Howells 			drop_nlink(d_inode(new_dentry));
8251da177e4SLinus Torvalds 		/* Don't oops if the victim was a dirent pointing to an
8261da177e4SLinus Torvalds 		   inode which didn't exist. */
8271da177e4SLinus Torvalds 		if (victim_f->inocache) {
828ced22070SDavid Woodhouse 			mutex_lock(&victim_f->sem);
829e36cb0b8SDavid Howells 			if (d_is_dir(new_dentry))
83027c72b04SDavid Woodhouse 				victim_f->inocache->pino_nlink = 0;
83127c72b04SDavid Woodhouse 			else
83227c72b04SDavid Woodhouse 				victim_f->inocache->pino_nlink--;
833ced22070SDavid Woodhouse 			mutex_unlock(&victim_f->sem);
8341da177e4SLinus Torvalds 		}
8351da177e4SLinus Torvalds 	}
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	/* If it was a directory we moved, and there was no victim,
8381da177e4SLinus Torvalds 	   increase i_nlink on its new parent */
839e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry) && !victim_f)
840d8c76e6fSDave Hansen 		inc_nlink(new_dir_i);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	/* Unlink the original */
8431da177e4SLinus Torvalds 	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
8443a69e0cdSArtem B. Bityutskiy 			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 	/* We don't touch inode->i_nlink */
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (ret) {
8491da177e4SLinus Torvalds 		/* Oh shit. We really ought to make a single node which can do both atomically */
8502b0143b5SDavid Howells 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
851ced22070SDavid Woodhouse 		mutex_lock(&f->sem);
8522b0143b5SDavid Howells 		inc_nlink(d_inode(old_dentry));
853e36cb0b8SDavid Howells 		if (f->inocache && !d_is_dir(old_dentry))
85427c72b04SDavid Woodhouse 			f->inocache->pino_nlink++;
855ced22070SDavid Woodhouse 		mutex_unlock(&f->sem);
8561da177e4SLinus Torvalds 
857da320f05SJoe Perches 		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
858da320f05SJoe Perches 			  __func__, ret);
859f9381284SAl Viro 		/*
860f9381284SAl Viro 		 * We can't keep the target in dcache after that.
861f9381284SAl Viro 		 * For one thing, we can't afford dentry aliases for directories.
862f9381284SAl Viro 		 * For another, if there was a victim, we _can't_ set new inode
863f9381284SAl Viro 		 * for that sucker and we have to trigger mount eviction - the
864f9381284SAl Viro 		 * caller won't do it on its own since we are returning an error.
865f9381284SAl Viro 		 */
866f9381284SAl Viro 		d_invalidate(new_dentry);
867c4592b9cSArnd Bergmann 		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
8681da177e4SLinus Torvalds 		return ret;
8691da177e4SLinus Torvalds 	}
8701da177e4SLinus Torvalds 
871e36cb0b8SDavid Howells 	if (d_is_dir(old_dentry))
8729a53c3a7SDave Hansen 		drop_nlink(old_dir_i);
8731da177e4SLinus Torvalds 
874c4592b9cSArnd Bergmann 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
8753a69e0cdSArtem B. Bityutskiy 
8761da177e4SLinus Torvalds 	return 0;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds 
879