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