18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
58c2ecf20Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/fs.h>
188c2ecf20Sopenharmony_ci#include <linux/crc32.h>
198c2ecf20Sopenharmony_ci#include <linux/jffs2.h>
208c2ecf20Sopenharmony_ci#include "jffs2_fs_i.h"
218c2ecf20Sopenharmony_ci#include "jffs2_fs_sb.h"
228c2ecf20Sopenharmony_ci#include <linux/time.h>
238c2ecf20Sopenharmony_ci#include "nodelist.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic int jffs2_readdir (struct file *, struct dir_context *);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic int jffs2_create (struct inode *,struct dentry *,umode_t,
288c2ecf20Sopenharmony_ci			 bool);
298c2ecf20Sopenharmony_cistatic struct dentry *jffs2_lookup (struct inode *,struct dentry *,
308c2ecf20Sopenharmony_ci				    unsigned int);
318c2ecf20Sopenharmony_cistatic int jffs2_link (struct dentry *,struct inode *,struct dentry *);
328c2ecf20Sopenharmony_cistatic int jffs2_unlink (struct inode *,struct dentry *);
338c2ecf20Sopenharmony_cistatic int jffs2_symlink (struct inode *,struct dentry *,const char *);
348c2ecf20Sopenharmony_cistatic int jffs2_mkdir (struct inode *,struct dentry *,umode_t);
358c2ecf20Sopenharmony_cistatic int jffs2_rmdir (struct inode *,struct dentry *);
368c2ecf20Sopenharmony_cistatic int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
378c2ecf20Sopenharmony_cistatic int jffs2_rename (struct inode *, struct dentry *,
388c2ecf20Sopenharmony_ci			 struct inode *, struct dentry *,
398c2ecf20Sopenharmony_ci			 unsigned int);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciconst struct file_operations jffs2_dir_operations =
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	.read =		generic_read_dir,
448c2ecf20Sopenharmony_ci	.iterate_shared=jffs2_readdir,
458c2ecf20Sopenharmony_ci	.unlocked_ioctl=jffs2_ioctl,
468c2ecf20Sopenharmony_ci	.fsync =	jffs2_fsync,
478c2ecf20Sopenharmony_ci	.llseek =	generic_file_llseek,
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciconst struct inode_operations jffs2_dir_inode_operations =
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	.create =	jffs2_create,
548c2ecf20Sopenharmony_ci	.lookup =	jffs2_lookup,
558c2ecf20Sopenharmony_ci	.link =		jffs2_link,
568c2ecf20Sopenharmony_ci	.unlink =	jffs2_unlink,
578c2ecf20Sopenharmony_ci	.symlink =	jffs2_symlink,
588c2ecf20Sopenharmony_ci	.mkdir =	jffs2_mkdir,
598c2ecf20Sopenharmony_ci	.rmdir =	jffs2_rmdir,
608c2ecf20Sopenharmony_ci	.mknod =	jffs2_mknod,
618c2ecf20Sopenharmony_ci	.rename =	jffs2_rename,
628c2ecf20Sopenharmony_ci	.get_acl =	jffs2_get_acl,
638c2ecf20Sopenharmony_ci	.set_acl =	jffs2_set_acl,
648c2ecf20Sopenharmony_ci	.setattr =	jffs2_setattr,
658c2ecf20Sopenharmony_ci	.listxattr =	jffs2_listxattr,
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/***********************************************************************/
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* We keep the dirent list sorted in increasing order of name hash,
728c2ecf20Sopenharmony_ci   and we use the same hash function as the dentries. Makes this
738c2ecf20Sopenharmony_ci   nice and simple
748c2ecf20Sopenharmony_ci*/
758c2ecf20Sopenharmony_cistatic struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
768c2ecf20Sopenharmony_ci				   unsigned int flags)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct jffs2_inode_info *dir_f;
798c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd = NULL, *fd_list;
808c2ecf20Sopenharmony_ci	uint32_t ino = 0;
818c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
828c2ecf20Sopenharmony_ci	unsigned int nhash;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	jffs2_dbg(1, "jffs2_lookup()\n");
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
878c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	dir_f = JFFS2_INODE_INFO(dir_i);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* The 'nhash' on the fd_list is not the same as the dentry hash */
928c2ecf20Sopenharmony_ci	nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	mutex_lock(&dir_f->sem);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
978c2ecf20Sopenharmony_ci	for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
988c2ecf20Sopenharmony_ci		if (fd_list->nhash == nhash &&
998c2ecf20Sopenharmony_ci		    (!fd || fd_list->version > fd->version) &&
1008c2ecf20Sopenharmony_ci		    strlen(fd_list->name) == target->d_name.len &&
1018c2ecf20Sopenharmony_ci		    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
1028c2ecf20Sopenharmony_ci			fd = fd_list;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	if (fd)
1068c2ecf20Sopenharmony_ci		ino = fd->ino;
1078c2ecf20Sopenharmony_ci	mutex_unlock(&dir_f->sem);
1088c2ecf20Sopenharmony_ci	if (ino) {
1098c2ecf20Sopenharmony_ci		inode = jffs2_iget(dir_i->i_sb, ino);
1108c2ecf20Sopenharmony_ci		if (IS_ERR(inode))
1118c2ecf20Sopenharmony_ci			pr_warn("iget() failed for ino #%u\n", ino);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return d_splice_alias(inode, target);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/***********************************************************************/
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int jffs2_readdir(struct file *file, struct dir_context *ctx)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
1238c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1248c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
1258c2ecf20Sopenharmony_ci	unsigned long curofs = 1;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (!dir_emit_dots(file, ctx))
1308c2ecf20Sopenharmony_ci		return 0;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	mutex_lock(&f->sem);
1338c2ecf20Sopenharmony_ci	for (fd = f->dents; fd; fd = fd->next) {
1348c2ecf20Sopenharmony_ci		curofs++;
1358c2ecf20Sopenharmony_ci		/* First loop: curofs = 2; pos = 2 */
1368c2ecf20Sopenharmony_ci		if (curofs < ctx->pos) {
1378c2ecf20Sopenharmony_ci			jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
1388c2ecf20Sopenharmony_ci				  fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos);
1398c2ecf20Sopenharmony_ci			continue;
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci		if (!fd->ino) {
1428c2ecf20Sopenharmony_ci			jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
1438c2ecf20Sopenharmony_ci				  fd->name);
1448c2ecf20Sopenharmony_ci			ctx->pos++;
1458c2ecf20Sopenharmony_ci			continue;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
1488c2ecf20Sopenharmony_ci			  (unsigned long)ctx->pos, fd->name, fd->ino, fd->type);
1498c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type))
1508c2ecf20Sopenharmony_ci			break;
1518c2ecf20Sopenharmony_ci		ctx->pos++;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
1548c2ecf20Sopenharmony_ci	return 0;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/***********************************************************************/
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int jffs2_create(struct inode *dir_i, struct dentry *dentry,
1618c2ecf20Sopenharmony_ci			umode_t mode, bool excl)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct jffs2_raw_inode *ri;
1648c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f, *dir_f;
1658c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c;
1668c2ecf20Sopenharmony_ci	struct inode *inode;
1678c2ecf20Sopenharmony_ci	int ret;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	ri = jffs2_alloc_raw_inode();
1708c2ecf20Sopenharmony_ci	if (!ri)
1718c2ecf20Sopenharmony_ci		return -ENOMEM;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	c = JFFS2_SB_INFO(dir_i->i_sb);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	jffs2_dbg(1, "%s()\n", __func__);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	inode = jffs2_new_inode(dir_i, mode, ri);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
1808c2ecf20Sopenharmony_ci		jffs2_dbg(1, "jffs2_new_inode() failed\n");
1818c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
1828c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	inode->i_op = &jffs2_file_inode_operations;
1868c2ecf20Sopenharmony_ci	inode->i_fop = &jffs2_file_operations;
1878c2ecf20Sopenharmony_ci	inode->i_mapping->a_ops = &jffs2_file_address_operations;
1888c2ecf20Sopenharmony_ci	inode->i_mapping->nrpages = 0;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	f = JFFS2_INODE_INFO(inode);
1918c2ecf20Sopenharmony_ci	dir_f = JFFS2_INODE_INFO(dir_i);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* jffs2_do_create() will want to lock it, _after_ reserving
1948c2ecf20Sopenharmony_ci	   space and taking c-alloc_sem. If we keep it locked here,
1958c2ecf20Sopenharmony_ci	   lockdep gets unhappy (although it's a false positive;
1968c2ecf20Sopenharmony_ci	   nothing else will be looking at this inode yet so there's
1978c2ecf20Sopenharmony_ci	   no chance of AB-BA deadlock involving its f->sem). */
1988c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
2018c2ecf20Sopenharmony_ci	if (ret)
2028c2ecf20Sopenharmony_ci		goto fail;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	jffs2_free_raw_inode(ri);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
2098c2ecf20Sopenharmony_ci		  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
2108c2ecf20Sopenharmony_ci		  f->inocache->pino_nlink, inode->i_mapping->nrpages);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci fail:
2168c2ecf20Sopenharmony_ci	iget_failed(inode);
2178c2ecf20Sopenharmony_ci	jffs2_free_raw_inode(ri);
2188c2ecf20Sopenharmony_ci	return ret;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/***********************************************************************/
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
2278c2ecf20Sopenharmony_ci	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2288c2ecf20Sopenharmony_ci	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry));
2298c2ecf20Sopenharmony_ci	int ret;
2308c2ecf20Sopenharmony_ci	uint32_t now = JFFS2_NOW();
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
2338c2ecf20Sopenharmony_ci			      dentry->d_name.len, dead_f, now);
2348c2ecf20Sopenharmony_ci	if (dead_f->inocache)
2358c2ecf20Sopenharmony_ci		set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink);
2368c2ecf20Sopenharmony_ci	if (!ret)
2378c2ecf20Sopenharmony_ci		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2388c2ecf20Sopenharmony_ci	return ret;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci/***********************************************************************/
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb);
2468c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
2478c2ecf20Sopenharmony_ci	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
2488c2ecf20Sopenharmony_ci	int ret;
2498c2ecf20Sopenharmony_ci	uint8_t type;
2508c2ecf20Sopenharmony_ci	uint32_t now;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Don't let people make hard links to bad inodes. */
2538c2ecf20Sopenharmony_ci	if (!f->inocache)
2548c2ecf20Sopenharmony_ci		return -EIO;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (d_is_dir(old_dentry))
2578c2ecf20Sopenharmony_ci		return -EPERM;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* XXX: This is ugly */
2608c2ecf20Sopenharmony_ci	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
2618c2ecf20Sopenharmony_ci	if (!type) type = DT_REG;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	now = JFFS2_NOW();
2648c2ecf20Sopenharmony_ci	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!ret) {
2678c2ecf20Sopenharmony_ci		mutex_lock(&f->sem);
2688c2ecf20Sopenharmony_ci		set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink);
2698c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
2708c2ecf20Sopenharmony_ci		d_instantiate(dentry, d_inode(old_dentry));
2718c2ecf20Sopenharmony_ci		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
2728c2ecf20Sopenharmony_ci		ihold(d_inode(old_dentry));
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	return ret;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/***********************************************************************/
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f, *dir_f;
2828c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c;
2838c2ecf20Sopenharmony_ci	struct inode *inode;
2848c2ecf20Sopenharmony_ci	struct jffs2_raw_inode *ri;
2858c2ecf20Sopenharmony_ci	struct jffs2_raw_dirent *rd;
2868c2ecf20Sopenharmony_ci	struct jffs2_full_dnode *fn;
2878c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
2888c2ecf20Sopenharmony_ci	int namelen;
2898c2ecf20Sopenharmony_ci	uint32_t alloclen;
2908c2ecf20Sopenharmony_ci	int ret, targetlen = strlen(target);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* FIXME: If you care. We'd need to use frags for the target
2938c2ecf20Sopenharmony_ci	   if it grows much more than this */
2948c2ecf20Sopenharmony_ci	if (targetlen > 254)
2958c2ecf20Sopenharmony_ci		return -ENAMETOOLONG;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	ri = jffs2_alloc_raw_inode();
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (!ri)
3008c2ecf20Sopenharmony_ci		return -ENOMEM;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	c = JFFS2_SB_INFO(dir_i->i_sb);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Try to reserve enough space for both node and dirent.
3058c2ecf20Sopenharmony_ci	 * Just the node will do for now, though
3068c2ecf20Sopenharmony_ci	 */
3078c2ecf20Sopenharmony_ci	namelen = dentry->d_name.len;
3088c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen,
3098c2ecf20Sopenharmony_ci				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (ret) {
3128c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
3138c2ecf20Sopenharmony_ci		return ret;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
3198c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
3208c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
3218c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	inode->i_op = &jffs2_symlink_inode_operations;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	f = JFFS2_INODE_INFO(inode);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	inode->i_size = targetlen;
3298c2ecf20Sopenharmony_ci	ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
3308c2ecf20Sopenharmony_ci	ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
3318c2ecf20Sopenharmony_ci	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ri->compr = JFFS2_COMPR_NONE;
3348c2ecf20Sopenharmony_ci	ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
3358c2ecf20Sopenharmony_ci	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	jffs2_free_raw_inode(ri);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (IS_ERR(fn)) {
3428c2ecf20Sopenharmony_ci		/* Eeek. Wave bye bye */
3438c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
3448c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
3458c2ecf20Sopenharmony_ci		ret = PTR_ERR(fn);
3468c2ecf20Sopenharmony_ci		goto fail;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/* We use f->target field to store the target path. */
3508c2ecf20Sopenharmony_ci	f->target = kmemdup(target, targetlen + 1, GFP_KERNEL);
3518c2ecf20Sopenharmony_ci	if (!f->target) {
3528c2ecf20Sopenharmony_ci		pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1);
3538c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
3548c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
3558c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3568c2ecf20Sopenharmony_ci		goto fail;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	inode->i_link = f->target;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
3618c2ecf20Sopenharmony_ci		  __func__, (char *)f->target);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* No data here. Only a metadata node, which will be
3648c2ecf20Sopenharmony_ci	   obsoleted by the first data write
3658c2ecf20Sopenharmony_ci	*/
3668c2ecf20Sopenharmony_ci	f->metadata = fn;
3678c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
3728c2ecf20Sopenharmony_ci	if (ret)
3738c2ecf20Sopenharmony_ci		goto fail;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret = jffs2_init_acl_post(inode);
3768c2ecf20Sopenharmony_ci	if (ret)
3778c2ecf20Sopenharmony_ci		goto fail;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
3808c2ecf20Sopenharmony_ci				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
3818c2ecf20Sopenharmony_ci	if (ret)
3828c2ecf20Sopenharmony_ci		goto fail;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	rd = jffs2_alloc_raw_dirent();
3858c2ecf20Sopenharmony_ci	if (!rd) {
3868c2ecf20Sopenharmony_ci		/* Argh. Now we treat it like a normal delete */
3878c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
3888c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3898c2ecf20Sopenharmony_ci		goto fail;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	dir_f = JFFS2_INODE_INFO(dir_i);
3938c2ecf20Sopenharmony_ci	mutex_lock(&dir_f->sem);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
3968c2ecf20Sopenharmony_ci	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
3978c2ecf20Sopenharmony_ci	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
3988c2ecf20Sopenharmony_ci	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	rd->pino = cpu_to_je32(dir_i->i_ino);
4018c2ecf20Sopenharmony_ci	rd->version = cpu_to_je32(++dir_f->highest_version);
4028c2ecf20Sopenharmony_ci	rd->ino = cpu_to_je32(inode->i_ino);
4038c2ecf20Sopenharmony_ci	rd->mctime = cpu_to_je32(JFFS2_NOW());
4048c2ecf20Sopenharmony_ci	rd->nsize = namelen;
4058c2ecf20Sopenharmony_ci	rd->type = DT_LNK;
4068c2ecf20Sopenharmony_ci	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
4078c2ecf20Sopenharmony_ci	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (IS_ERR(fd)) {
4128c2ecf20Sopenharmony_ci		/* dirent failed to write. Delete the inode normally
4138c2ecf20Sopenharmony_ci		   as if it were the final unlink() */
4148c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
4158c2ecf20Sopenharmony_ci		jffs2_free_raw_dirent(rd);
4168c2ecf20Sopenharmony_ci		mutex_unlock(&dir_f->sem);
4178c2ecf20Sopenharmony_ci		ret = PTR_ERR(fd);
4188c2ecf20Sopenharmony_ci		goto fail;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	jffs2_free_raw_dirent(rd);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/* Link the fd into the inode's list, obsoleting an old
4268c2ecf20Sopenharmony_ci	   one if necessary. */
4278c2ecf20Sopenharmony_ci	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	mutex_unlock(&dir_f->sem);
4308c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci fail:
4368c2ecf20Sopenharmony_ci	iget_failed(inode);
4378c2ecf20Sopenharmony_ci	return ret;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f, *dir_f;
4448c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c;
4458c2ecf20Sopenharmony_ci	struct inode *inode;
4468c2ecf20Sopenharmony_ci	struct jffs2_raw_inode *ri;
4478c2ecf20Sopenharmony_ci	struct jffs2_raw_dirent *rd;
4488c2ecf20Sopenharmony_ci	struct jffs2_full_dnode *fn;
4498c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
4508c2ecf20Sopenharmony_ci	int namelen;
4518c2ecf20Sopenharmony_ci	uint32_t alloclen;
4528c2ecf20Sopenharmony_ci	int ret;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	mode |= S_IFDIR;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	ri = jffs2_alloc_raw_inode();
4578c2ecf20Sopenharmony_ci	if (!ri)
4588c2ecf20Sopenharmony_ci		return -ENOMEM;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	c = JFFS2_SB_INFO(dir_i->i_sb);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* Try to reserve enough space for both node and dirent.
4638c2ecf20Sopenharmony_ci	 * Just the node will do for now, though
4648c2ecf20Sopenharmony_ci	 */
4658c2ecf20Sopenharmony_ci	namelen = dentry->d_name.len;
4668c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
4678c2ecf20Sopenharmony_ci				  JFFS2_SUMMARY_INODE_SIZE);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (ret) {
4708c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
4718c2ecf20Sopenharmony_ci		return ret;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	inode = jffs2_new_inode(dir_i, mode, ri);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
4778c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
4788c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
4798c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	inode->i_op = &jffs2_dir_inode_operations;
4838c2ecf20Sopenharmony_ci	inode->i_fop = &jffs2_dir_operations;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	f = JFFS2_INODE_INFO(inode);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Directories get nlink 2 at start */
4888c2ecf20Sopenharmony_ci	set_nlink(inode, 2);
4898c2ecf20Sopenharmony_ci	/* but ic->pino_nlink is the parent ino# */
4908c2ecf20Sopenharmony_ci	f->inocache->pino_nlink = dir_i->i_ino;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	ri->data_crc = cpu_to_je32(0);
4938c2ecf20Sopenharmony_ci	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	jffs2_free_raw_inode(ri);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (IS_ERR(fn)) {
5008c2ecf20Sopenharmony_ci		/* Eeek. Wave bye bye */
5018c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
5028c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
5038c2ecf20Sopenharmony_ci		ret = PTR_ERR(fn);
5048c2ecf20Sopenharmony_ci		goto fail;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci	/* No data here. Only a metadata node, which will be
5078c2ecf20Sopenharmony_ci	   obsoleted by the first data write
5088c2ecf20Sopenharmony_ci	*/
5098c2ecf20Sopenharmony_ci	f->metadata = fn;
5108c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
5158c2ecf20Sopenharmony_ci	if (ret)
5168c2ecf20Sopenharmony_ci		goto fail;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	ret = jffs2_init_acl_post(inode);
5198c2ecf20Sopenharmony_ci	if (ret)
5208c2ecf20Sopenharmony_ci		goto fail;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
5238c2ecf20Sopenharmony_ci				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
5248c2ecf20Sopenharmony_ci	if (ret)
5258c2ecf20Sopenharmony_ci		goto fail;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	rd = jffs2_alloc_raw_dirent();
5288c2ecf20Sopenharmony_ci	if (!rd) {
5298c2ecf20Sopenharmony_ci		/* Argh. Now we treat it like a normal delete */
5308c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
5318c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5328c2ecf20Sopenharmony_ci		goto fail;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	dir_f = JFFS2_INODE_INFO(dir_i);
5368c2ecf20Sopenharmony_ci	mutex_lock(&dir_f->sem);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
5398c2ecf20Sopenharmony_ci	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
5408c2ecf20Sopenharmony_ci	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
5418c2ecf20Sopenharmony_ci	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	rd->pino = cpu_to_je32(dir_i->i_ino);
5448c2ecf20Sopenharmony_ci	rd->version = cpu_to_je32(++dir_f->highest_version);
5458c2ecf20Sopenharmony_ci	rd->ino = cpu_to_je32(inode->i_ino);
5468c2ecf20Sopenharmony_ci	rd->mctime = cpu_to_je32(JFFS2_NOW());
5478c2ecf20Sopenharmony_ci	rd->nsize = namelen;
5488c2ecf20Sopenharmony_ci	rd->type = DT_DIR;
5498c2ecf20Sopenharmony_ci	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
5508c2ecf20Sopenharmony_ci	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (IS_ERR(fd)) {
5558c2ecf20Sopenharmony_ci		/* dirent failed to write. Delete the inode normally
5568c2ecf20Sopenharmony_ci		   as if it were the final unlink() */
5578c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
5588c2ecf20Sopenharmony_ci		jffs2_free_raw_dirent(rd);
5598c2ecf20Sopenharmony_ci		mutex_unlock(&dir_f->sem);
5608c2ecf20Sopenharmony_ci		ret = PTR_ERR(fd);
5618c2ecf20Sopenharmony_ci		goto fail;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
5658c2ecf20Sopenharmony_ci	inc_nlink(dir_i);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	jffs2_free_raw_dirent(rd);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* Link the fd into the inode's list, obsoleting an old
5708c2ecf20Sopenharmony_ci	   one if necessary. */
5718c2ecf20Sopenharmony_ci	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	mutex_unlock(&dir_f->sem);
5748c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
5778c2ecf20Sopenharmony_ci	return 0;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci fail:
5808c2ecf20Sopenharmony_ci	iget_failed(inode);
5818c2ecf20Sopenharmony_ci	return ret;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
5878c2ecf20Sopenharmony_ci	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
5888c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
5898c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
5908c2ecf20Sopenharmony_ci	int ret;
5918c2ecf20Sopenharmony_ci	uint32_t now = JFFS2_NOW();
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	mutex_lock(&f->sem);
5948c2ecf20Sopenharmony_ci	for (fd = f->dents ; fd; fd = fd->next) {
5958c2ecf20Sopenharmony_ci		if (fd->ino) {
5968c2ecf20Sopenharmony_ci			mutex_unlock(&f->sem);
5978c2ecf20Sopenharmony_ci			return -ENOTEMPTY;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
6038c2ecf20Sopenharmony_ci			      dentry->d_name.len, f, now);
6048c2ecf20Sopenharmony_ci	if (!ret) {
6058c2ecf20Sopenharmony_ci		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
6068c2ecf20Sopenharmony_ci		clear_nlink(d_inode(dentry));
6078c2ecf20Sopenharmony_ci		drop_nlink(dir_i);
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	return ret;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f, *dir_f;
6158c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c;
6168c2ecf20Sopenharmony_ci	struct inode *inode;
6178c2ecf20Sopenharmony_ci	struct jffs2_raw_inode *ri;
6188c2ecf20Sopenharmony_ci	struct jffs2_raw_dirent *rd;
6198c2ecf20Sopenharmony_ci	struct jffs2_full_dnode *fn;
6208c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
6218c2ecf20Sopenharmony_ci	int namelen;
6228c2ecf20Sopenharmony_ci	union jffs2_device_node dev;
6238c2ecf20Sopenharmony_ci	int devlen = 0;
6248c2ecf20Sopenharmony_ci	uint32_t alloclen;
6258c2ecf20Sopenharmony_ci	int ret;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	ri = jffs2_alloc_raw_inode();
6288c2ecf20Sopenharmony_ci	if (!ri)
6298c2ecf20Sopenharmony_ci		return -ENOMEM;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	c = JFFS2_SB_INFO(dir_i->i_sb);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (S_ISBLK(mode) || S_ISCHR(mode))
6348c2ecf20Sopenharmony_ci		devlen = jffs2_encode_dev(&dev, rdev);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* Try to reserve enough space for both node and dirent.
6378c2ecf20Sopenharmony_ci	 * Just the node will do for now, though
6388c2ecf20Sopenharmony_ci	 */
6398c2ecf20Sopenharmony_ci	namelen = dentry->d_name.len;
6408c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen,
6418c2ecf20Sopenharmony_ci				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (ret) {
6448c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
6458c2ecf20Sopenharmony_ci		return ret;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	inode = jffs2_new_inode(dir_i, mode, ri);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
6518c2ecf20Sopenharmony_ci		jffs2_free_raw_inode(ri);
6528c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
6538c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci	inode->i_op = &jffs2_file_inode_operations;
6568c2ecf20Sopenharmony_ci	init_special_inode(inode, inode->i_mode, rdev);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	f = JFFS2_INODE_INFO(inode);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	ri->dsize = ri->csize = cpu_to_je32(devlen);
6618c2ecf20Sopenharmony_ci	ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
6628c2ecf20Sopenharmony_ci	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	ri->compr = JFFS2_COMPR_NONE;
6658c2ecf20Sopenharmony_ci	ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
6668c2ecf20Sopenharmony_ci	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	jffs2_free_raw_inode(ri);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (IS_ERR(fn)) {
6738c2ecf20Sopenharmony_ci		/* Eeek. Wave bye bye */
6748c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
6758c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
6768c2ecf20Sopenharmony_ci		ret = PTR_ERR(fn);
6778c2ecf20Sopenharmony_ci		goto fail;
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci	/* No data here. Only a metadata node, which will be
6808c2ecf20Sopenharmony_ci	   obsoleted by the first data write
6818c2ecf20Sopenharmony_ci	*/
6828c2ecf20Sopenharmony_ci	f->metadata = fn;
6838c2ecf20Sopenharmony_ci	mutex_unlock(&f->sem);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
6888c2ecf20Sopenharmony_ci	if (ret)
6898c2ecf20Sopenharmony_ci		goto fail;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	ret = jffs2_init_acl_post(inode);
6928c2ecf20Sopenharmony_ci	if (ret)
6938c2ecf20Sopenharmony_ci		goto fail;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
6968c2ecf20Sopenharmony_ci				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
6978c2ecf20Sopenharmony_ci	if (ret)
6988c2ecf20Sopenharmony_ci		goto fail;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	rd = jffs2_alloc_raw_dirent();
7018c2ecf20Sopenharmony_ci	if (!rd) {
7028c2ecf20Sopenharmony_ci		/* Argh. Now we treat it like a normal delete */
7038c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
7048c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7058c2ecf20Sopenharmony_ci		goto fail;
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	dir_f = JFFS2_INODE_INFO(dir_i);
7098c2ecf20Sopenharmony_ci	mutex_lock(&dir_f->sem);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
7128c2ecf20Sopenharmony_ci	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
7138c2ecf20Sopenharmony_ci	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
7148c2ecf20Sopenharmony_ci	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	rd->pino = cpu_to_je32(dir_i->i_ino);
7178c2ecf20Sopenharmony_ci	rd->version = cpu_to_je32(++dir_f->highest_version);
7188c2ecf20Sopenharmony_ci	rd->ino = cpu_to_je32(inode->i_ino);
7198c2ecf20Sopenharmony_ci	rd->mctime = cpu_to_je32(JFFS2_NOW());
7208c2ecf20Sopenharmony_ci	rd->nsize = namelen;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* XXX: This is ugly. */
7238c2ecf20Sopenharmony_ci	rd->type = (mode & S_IFMT) >> 12;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
7268c2ecf20Sopenharmony_ci	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	if (IS_ERR(fd)) {
7318c2ecf20Sopenharmony_ci		/* dirent failed to write. Delete the inode normally
7328c2ecf20Sopenharmony_ci		   as if it were the final unlink() */
7338c2ecf20Sopenharmony_ci		jffs2_complete_reservation(c);
7348c2ecf20Sopenharmony_ci		jffs2_free_raw_dirent(rd);
7358c2ecf20Sopenharmony_ci		mutex_unlock(&dir_f->sem);
7368c2ecf20Sopenharmony_ci		ret = PTR_ERR(fd);
7378c2ecf20Sopenharmony_ci		goto fail;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	jffs2_free_raw_dirent(rd);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	/* Link the fd into the inode's list, obsoleting an old
7458c2ecf20Sopenharmony_ci	   one if necessary. */
7468c2ecf20Sopenharmony_ci	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	mutex_unlock(&dir_f->sem);
7498c2ecf20Sopenharmony_ci	jffs2_complete_reservation(c);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
7528c2ecf20Sopenharmony_ci	return 0;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci fail:
7558c2ecf20Sopenharmony_ci	iget_failed(inode);
7568c2ecf20Sopenharmony_ci	return ret;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
7608c2ecf20Sopenharmony_ci			 struct inode *new_dir_i, struct dentry *new_dentry,
7618c2ecf20Sopenharmony_ci			 unsigned int flags)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	int ret;
7648c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
7658c2ecf20Sopenharmony_ci	struct jffs2_inode_info *victim_f = NULL;
7668c2ecf20Sopenharmony_ci	uint8_t type;
7678c2ecf20Sopenharmony_ci	uint32_t now;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (flags & ~RENAME_NOREPLACE)
7708c2ecf20Sopenharmony_ci		return -EINVAL;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* The VFS will check for us and prevent trying to rename a
7738c2ecf20Sopenharmony_ci	 * file over a directory and vice versa, but if it's a directory,
7748c2ecf20Sopenharmony_ci	 * the VFS can't check whether the victim is empty. The filesystem
7758c2ecf20Sopenharmony_ci	 * needs to do that for itself.
7768c2ecf20Sopenharmony_ci	 */
7778c2ecf20Sopenharmony_ci	if (d_really_is_positive(new_dentry)) {
7788c2ecf20Sopenharmony_ci		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
7798c2ecf20Sopenharmony_ci		if (d_is_dir(new_dentry)) {
7808c2ecf20Sopenharmony_ci			struct jffs2_full_dirent *fd;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci			mutex_lock(&victim_f->sem);
7838c2ecf20Sopenharmony_ci			for (fd = victim_f->dents; fd; fd = fd->next) {
7848c2ecf20Sopenharmony_ci				if (fd->ino) {
7858c2ecf20Sopenharmony_ci					mutex_unlock(&victim_f->sem);
7868c2ecf20Sopenharmony_ci					return -ENOTEMPTY;
7878c2ecf20Sopenharmony_ci				}
7888c2ecf20Sopenharmony_ci			}
7898c2ecf20Sopenharmony_ci			mutex_unlock(&victim_f->sem);
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/* XXX: We probably ought to alloc enough space for
7948c2ecf20Sopenharmony_ci	   both nodes at the same time. Writing the new link,
7958c2ecf20Sopenharmony_ci	   then getting -ENOSPC, is quite bad :)
7968c2ecf20Sopenharmony_ci	*/
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* Make a hard link */
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	/* XXX: This is ugly */
8018c2ecf20Sopenharmony_ci	type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
8028c2ecf20Sopenharmony_ci	if (!type) type = DT_REG;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	now = JFFS2_NOW();
8058c2ecf20Sopenharmony_ci	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
8068c2ecf20Sopenharmony_ci			    d_inode(old_dentry)->i_ino, type,
8078c2ecf20Sopenharmony_ci			    new_dentry->d_name.name, new_dentry->d_name.len, now);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (ret)
8108c2ecf20Sopenharmony_ci		return ret;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (victim_f) {
8138c2ecf20Sopenharmony_ci		/* There was a victim. Kill it off nicely */
8148c2ecf20Sopenharmony_ci		if (d_is_dir(new_dentry))
8158c2ecf20Sopenharmony_ci			clear_nlink(d_inode(new_dentry));
8168c2ecf20Sopenharmony_ci		else
8178c2ecf20Sopenharmony_ci			drop_nlink(d_inode(new_dentry));
8188c2ecf20Sopenharmony_ci		/* Don't oops if the victim was a dirent pointing to an
8198c2ecf20Sopenharmony_ci		   inode which didn't exist. */
8208c2ecf20Sopenharmony_ci		if (victim_f->inocache) {
8218c2ecf20Sopenharmony_ci			mutex_lock(&victim_f->sem);
8228c2ecf20Sopenharmony_ci			if (d_is_dir(new_dentry))
8238c2ecf20Sopenharmony_ci				victim_f->inocache->pino_nlink = 0;
8248c2ecf20Sopenharmony_ci			else
8258c2ecf20Sopenharmony_ci				victim_f->inocache->pino_nlink--;
8268c2ecf20Sopenharmony_ci			mutex_unlock(&victim_f->sem);
8278c2ecf20Sopenharmony_ci		}
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/* If it was a directory we moved, and there was no victim,
8318c2ecf20Sopenharmony_ci	   increase i_nlink on its new parent */
8328c2ecf20Sopenharmony_ci	if (d_is_dir(old_dentry) && !victim_f)
8338c2ecf20Sopenharmony_ci		inc_nlink(new_dir_i);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/* Unlink the original */
8368c2ecf20Sopenharmony_ci	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
8378c2ecf20Sopenharmony_ci			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	/* We don't touch inode->i_nlink */
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	if (ret) {
8428c2ecf20Sopenharmony_ci		/* Oh shit. We really ought to make a single node which can do both atomically */
8438c2ecf20Sopenharmony_ci		struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
8448c2ecf20Sopenharmony_ci		mutex_lock(&f->sem);
8458c2ecf20Sopenharmony_ci		inc_nlink(d_inode(old_dentry));
8468c2ecf20Sopenharmony_ci		if (f->inocache && !d_is_dir(old_dentry))
8478c2ecf20Sopenharmony_ci			f->inocache->pino_nlink++;
8488c2ecf20Sopenharmony_ci		mutex_unlock(&f->sem);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
8518c2ecf20Sopenharmony_ci			  __func__, ret);
8528c2ecf20Sopenharmony_ci		/*
8538c2ecf20Sopenharmony_ci		 * We can't keep the target in dcache after that.
8548c2ecf20Sopenharmony_ci		 * For one thing, we can't afford dentry aliases for directories.
8558c2ecf20Sopenharmony_ci		 * For another, if there was a victim, we _can't_ set new inode
8568c2ecf20Sopenharmony_ci		 * for that sucker and we have to trigger mount eviction - the
8578c2ecf20Sopenharmony_ci		 * caller won't do it on its own since we are returning an error.
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		d_invalidate(new_dentry);
8608c2ecf20Sopenharmony_ci		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
8618c2ecf20Sopenharmony_ci		return ret;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (d_is_dir(old_dentry))
8658c2ecf20Sopenharmony_ci		drop_nlink(old_dir_i);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	return 0;
8708c2ecf20Sopenharmony_ci}
8718c2ecf20Sopenharmony_ci
872