162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/fs.h> 1862306a36Sopenharmony_ci#include <linux/crc32.h> 1962306a36Sopenharmony_ci#include <linux/jffs2.h> 2062306a36Sopenharmony_ci#include "jffs2_fs_i.h" 2162306a36Sopenharmony_ci#include "jffs2_fs_sb.h" 2262306a36Sopenharmony_ci#include <linux/time.h> 2362306a36Sopenharmony_ci#include "nodelist.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int jffs2_readdir (struct file *, struct dir_context *); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int jffs2_create (struct mnt_idmap *, struct inode *, 2862306a36Sopenharmony_ci struct dentry *, umode_t, bool); 2962306a36Sopenharmony_cistatic struct dentry *jffs2_lookup (struct inode *,struct dentry *, 3062306a36Sopenharmony_ci unsigned int); 3162306a36Sopenharmony_cistatic int jffs2_link (struct dentry *,struct inode *,struct dentry *); 3262306a36Sopenharmony_cistatic int jffs2_unlink (struct inode *,struct dentry *); 3362306a36Sopenharmony_cistatic int jffs2_symlink (struct mnt_idmap *, struct inode *, 3462306a36Sopenharmony_ci struct dentry *, const char *); 3562306a36Sopenharmony_cistatic int jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, 3662306a36Sopenharmony_ci umode_t); 3762306a36Sopenharmony_cistatic int jffs2_rmdir (struct inode *,struct dentry *); 3862306a36Sopenharmony_cistatic int jffs2_mknod (struct mnt_idmap *, struct inode *,struct dentry *, 3962306a36Sopenharmony_ci umode_t,dev_t); 4062306a36Sopenharmony_cistatic int jffs2_rename (struct mnt_idmap *, struct inode *, 4162306a36Sopenharmony_ci struct dentry *, struct inode *, struct dentry *, 4262306a36Sopenharmony_ci unsigned int); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciconst struct file_operations jffs2_dir_operations = 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci .read = generic_read_dir, 4762306a36Sopenharmony_ci .iterate_shared=jffs2_readdir, 4862306a36Sopenharmony_ci .unlocked_ioctl=jffs2_ioctl, 4962306a36Sopenharmony_ci .fsync = jffs2_fsync, 5062306a36Sopenharmony_ci .llseek = generic_file_llseek, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciconst struct inode_operations jffs2_dir_inode_operations = 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci .create = jffs2_create, 5762306a36Sopenharmony_ci .lookup = jffs2_lookup, 5862306a36Sopenharmony_ci .link = jffs2_link, 5962306a36Sopenharmony_ci .unlink = jffs2_unlink, 6062306a36Sopenharmony_ci .symlink = jffs2_symlink, 6162306a36Sopenharmony_ci .mkdir = jffs2_mkdir, 6262306a36Sopenharmony_ci .rmdir = jffs2_rmdir, 6362306a36Sopenharmony_ci .mknod = jffs2_mknod, 6462306a36Sopenharmony_ci .rename = jffs2_rename, 6562306a36Sopenharmony_ci .get_inode_acl = jffs2_get_acl, 6662306a36Sopenharmony_ci .set_acl = jffs2_set_acl, 6762306a36Sopenharmony_ci .setattr = jffs2_setattr, 6862306a36Sopenharmony_ci .listxattr = jffs2_listxattr, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/***********************************************************************/ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* We keep the dirent list sorted in increasing order of name hash, 7562306a36Sopenharmony_ci and we use the same hash function as the dentries. Makes this 7662306a36Sopenharmony_ci nice and simple 7762306a36Sopenharmony_ci*/ 7862306a36Sopenharmony_cistatic struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, 7962306a36Sopenharmony_ci unsigned int flags) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct jffs2_inode_info *dir_f; 8262306a36Sopenharmony_ci struct jffs2_full_dirent *fd = NULL, *fd_list; 8362306a36Sopenharmony_ci uint32_t ino = 0; 8462306a36Sopenharmony_ci struct inode *inode = NULL; 8562306a36Sopenharmony_ci unsigned int nhash; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_lookup()\n"); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (target->d_name.len > JFFS2_MAX_NAME_LEN) 9062306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci dir_f = JFFS2_INODE_INFO(dir_i); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* The 'nhash' on the fd_list is not the same as the dentry hash */ 9562306a36Sopenharmony_ci nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci mutex_lock(&dir_f->sem); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ 10062306a36Sopenharmony_ci for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) { 10162306a36Sopenharmony_ci if (fd_list->nhash == nhash && 10262306a36Sopenharmony_ci (!fd || fd_list->version > fd->version) && 10362306a36Sopenharmony_ci strlen(fd_list->name) == target->d_name.len && 10462306a36Sopenharmony_ci !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { 10562306a36Sopenharmony_ci fd = fd_list; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci if (fd) 10962306a36Sopenharmony_ci ino = fd->ino; 11062306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 11162306a36Sopenharmony_ci if (ino) { 11262306a36Sopenharmony_ci inode = jffs2_iget(dir_i->i_sb, ino); 11362306a36Sopenharmony_ci if (IS_ERR(inode)) 11462306a36Sopenharmony_ci pr_warn("iget() failed for ino #%u\n", ino); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return d_splice_alias(inode, target); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/***********************************************************************/ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int jffs2_readdir(struct file *file, struct dir_context *ctx) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct inode *inode = file_inode(file); 12662306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 12762306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 12862306a36Sopenharmony_ci unsigned long curofs = 1; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci mutex_lock(&f->sem); 13662306a36Sopenharmony_ci for (fd = f->dents; fd; fd = fd->next) { 13762306a36Sopenharmony_ci curofs++; 13862306a36Sopenharmony_ci /* First loop: curofs = 2; pos = 2 */ 13962306a36Sopenharmony_ci if (curofs < ctx->pos) { 14062306a36Sopenharmony_ci jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", 14162306a36Sopenharmony_ci fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos); 14262306a36Sopenharmony_ci continue; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci if (!fd->ino) { 14562306a36Sopenharmony_ci jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n", 14662306a36Sopenharmony_ci fd->name); 14762306a36Sopenharmony_ci ctx->pos++; 14862306a36Sopenharmony_ci continue; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n", 15162306a36Sopenharmony_ci (unsigned long)ctx->pos, fd->name, fd->ino, fd->type); 15262306a36Sopenharmony_ci if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type)) 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci ctx->pos++; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci mutex_unlock(&f->sem); 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/***********************************************************************/ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int jffs2_create(struct mnt_idmap *idmap, struct inode *dir_i, 16462306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool excl) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct jffs2_raw_inode *ri; 16762306a36Sopenharmony_ci struct jffs2_inode_info *f, *dir_f; 16862306a36Sopenharmony_ci struct jffs2_sb_info *c; 16962306a36Sopenharmony_ci struct inode *inode; 17062306a36Sopenharmony_ci int ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ri = jffs2_alloc_raw_inode(); 17362306a36Sopenharmony_ci if (!ri) 17462306a36Sopenharmony_ci return -ENOMEM; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci c = JFFS2_SB_INFO(dir_i->i_sb); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci jffs2_dbg(1, "%s()\n", __func__); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci inode = jffs2_new_inode(dir_i, mode, ri); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (IS_ERR(inode)) { 18362306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_new_inode() failed\n"); 18462306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 18562306a36Sopenharmony_ci return PTR_ERR(inode); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci inode->i_op = &jffs2_file_inode_operations; 18962306a36Sopenharmony_ci inode->i_fop = &jffs2_file_operations; 19062306a36Sopenharmony_ci inode->i_mapping->a_ops = &jffs2_file_address_operations; 19162306a36Sopenharmony_ci inode->i_mapping->nrpages = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 19462306a36Sopenharmony_ci dir_f = JFFS2_INODE_INFO(dir_i); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* jffs2_do_create() will want to lock it, _after_ reserving 19762306a36Sopenharmony_ci space and taking c-alloc_sem. If we keep it locked here, 19862306a36Sopenharmony_ci lockdep gets unhappy (although it's a false positive; 19962306a36Sopenharmony_ci nothing else will be looking at this inode yet so there's 20062306a36Sopenharmony_ci no chance of AB-BA deadlock involving its f->sem). */ 20162306a36Sopenharmony_ci mutex_unlock(&f->sem); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name); 20462306a36Sopenharmony_ci if (ret) 20562306a36Sopenharmony_ci goto fail; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, 20862306a36Sopenharmony_ci ITIME(je32_to_cpu(ri->ctime))); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", 21362306a36Sopenharmony_ci __func__, inode->i_ino, inode->i_mode, inode->i_nlink, 21462306a36Sopenharmony_ci f->inocache->pino_nlink, inode->i_mapping->nrpages); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci fail: 22062306a36Sopenharmony_ci iget_failed(inode); 22162306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 22262306a36Sopenharmony_ci return ret; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/***********************************************************************/ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); 23162306a36Sopenharmony_ci struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); 23262306a36Sopenharmony_ci struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry)); 23362306a36Sopenharmony_ci int ret; 23462306a36Sopenharmony_ci uint32_t now = JFFS2_NOW(); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 23762306a36Sopenharmony_ci dentry->d_name.len, dead_f, now); 23862306a36Sopenharmony_ci if (dead_f->inocache) 23962306a36Sopenharmony_ci set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink); 24062306a36Sopenharmony_ci if (!ret) 24162306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, ITIME(now)); 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci/***********************************************************************/ 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb); 25062306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); 25162306a36Sopenharmony_ci struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); 25262306a36Sopenharmony_ci int ret; 25362306a36Sopenharmony_ci uint8_t type; 25462306a36Sopenharmony_ci uint32_t now; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Don't let people make hard links to bad inodes. */ 25762306a36Sopenharmony_ci if (!f->inocache) 25862306a36Sopenharmony_ci return -EIO; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (d_is_dir(old_dentry)) 26162306a36Sopenharmony_ci return -EPERM; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* XXX: This is ugly */ 26462306a36Sopenharmony_ci type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; 26562306a36Sopenharmony_ci if (!type) type = DT_REG; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci now = JFFS2_NOW(); 26862306a36Sopenharmony_ci ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!ret) { 27162306a36Sopenharmony_ci mutex_lock(&f->sem); 27262306a36Sopenharmony_ci set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink); 27362306a36Sopenharmony_ci mutex_unlock(&f->sem); 27462306a36Sopenharmony_ci d_instantiate(dentry, d_inode(old_dentry)); 27562306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, ITIME(now)); 27662306a36Sopenharmony_ci ihold(d_inode(old_dentry)); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/***********************************************************************/ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i, 28462306a36Sopenharmony_ci struct dentry *dentry, const char *target) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct jffs2_inode_info *f, *dir_f; 28762306a36Sopenharmony_ci struct jffs2_sb_info *c; 28862306a36Sopenharmony_ci struct inode *inode; 28962306a36Sopenharmony_ci struct jffs2_raw_inode *ri; 29062306a36Sopenharmony_ci struct jffs2_raw_dirent *rd; 29162306a36Sopenharmony_ci struct jffs2_full_dnode *fn; 29262306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 29362306a36Sopenharmony_ci int namelen; 29462306a36Sopenharmony_ci uint32_t alloclen; 29562306a36Sopenharmony_ci int ret, targetlen = strlen(target); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* FIXME: If you care. We'd need to use frags for the target 29862306a36Sopenharmony_ci if it grows much more than this */ 29962306a36Sopenharmony_ci if (targetlen > 254) 30062306a36Sopenharmony_ci return -ENAMETOOLONG; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ri = jffs2_alloc_raw_inode(); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!ri) 30562306a36Sopenharmony_ci return -ENOMEM; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci c = JFFS2_SB_INFO(dir_i->i_sb); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Try to reserve enough space for both node and dirent. 31062306a36Sopenharmony_ci * Just the node will do for now, though 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci namelen = dentry->d_name.len; 31362306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen, 31462306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (ret) { 31762306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (IS_ERR(inode)) { 32462306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 32562306a36Sopenharmony_ci jffs2_complete_reservation(c); 32662306a36Sopenharmony_ci return PTR_ERR(inode); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci inode->i_op = &jffs2_symlink_inode_operations; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci inode->i_size = targetlen; 33462306a36Sopenharmony_ci ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); 33562306a36Sopenharmony_ci ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); 33662306a36Sopenharmony_ci ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ri->compr = JFFS2_COMPR_NONE; 33962306a36Sopenharmony_ci ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); 34062306a36Sopenharmony_ci ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (IS_ERR(fn)) { 34762306a36Sopenharmony_ci /* Eeek. Wave bye bye */ 34862306a36Sopenharmony_ci mutex_unlock(&f->sem); 34962306a36Sopenharmony_ci jffs2_complete_reservation(c); 35062306a36Sopenharmony_ci ret = PTR_ERR(fn); 35162306a36Sopenharmony_ci goto fail; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* We use f->target field to store the target path. */ 35562306a36Sopenharmony_ci f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); 35662306a36Sopenharmony_ci if (!f->target) { 35762306a36Sopenharmony_ci pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1); 35862306a36Sopenharmony_ci mutex_unlock(&f->sem); 35962306a36Sopenharmony_ci jffs2_complete_reservation(c); 36062306a36Sopenharmony_ci ret = -ENOMEM; 36162306a36Sopenharmony_ci goto fail; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci inode->i_link = f->target; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): symlink's target '%s' cached\n", 36662306a36Sopenharmony_ci __func__, (char *)f->target); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* No data here. Only a metadata node, which will be 36962306a36Sopenharmony_ci obsoleted by the first data write 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci f->metadata = fn; 37262306a36Sopenharmony_ci mutex_unlock(&f->sem); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci jffs2_complete_reservation(c); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ret = jffs2_init_security(inode, dir_i, &dentry->d_name); 37762306a36Sopenharmony_ci if (ret) 37862306a36Sopenharmony_ci goto fail; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci ret = jffs2_init_acl_post(inode); 38162306a36Sopenharmony_ci if (ret) 38262306a36Sopenharmony_ci goto fail; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, 38562306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci goto fail; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci rd = jffs2_alloc_raw_dirent(); 39062306a36Sopenharmony_ci if (!rd) { 39162306a36Sopenharmony_ci /* Argh. Now we treat it like a normal delete */ 39262306a36Sopenharmony_ci jffs2_complete_reservation(c); 39362306a36Sopenharmony_ci ret = -ENOMEM; 39462306a36Sopenharmony_ci goto fail; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci dir_f = JFFS2_INODE_INFO(dir_i); 39862306a36Sopenharmony_ci mutex_lock(&dir_f->sem); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 40162306a36Sopenharmony_ci rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 40262306a36Sopenharmony_ci rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 40362306a36Sopenharmony_ci rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci rd->pino = cpu_to_je32(dir_i->i_ino); 40662306a36Sopenharmony_ci rd->version = cpu_to_je32(++dir_f->highest_version); 40762306a36Sopenharmony_ci rd->ino = cpu_to_je32(inode->i_ino); 40862306a36Sopenharmony_ci rd->mctime = cpu_to_je32(JFFS2_NOW()); 40962306a36Sopenharmony_ci rd->nsize = namelen; 41062306a36Sopenharmony_ci rd->type = DT_LNK; 41162306a36Sopenharmony_ci rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 41262306a36Sopenharmony_ci rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (IS_ERR(fd)) { 41762306a36Sopenharmony_ci /* dirent failed to write. Delete the inode normally 41862306a36Sopenharmony_ci as if it were the final unlink() */ 41962306a36Sopenharmony_ci jffs2_complete_reservation(c); 42062306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 42162306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 42262306a36Sopenharmony_ci ret = PTR_ERR(fd); 42362306a36Sopenharmony_ci goto fail; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, 42762306a36Sopenharmony_ci ITIME(je32_to_cpu(rd->mctime))); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Link the fd into the inode's list, obsoleting an old 43262306a36Sopenharmony_ci one if necessary. */ 43362306a36Sopenharmony_ci jffs2_add_fd_to_list(c, fd, &dir_f->dents); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 43662306a36Sopenharmony_ci jffs2_complete_reservation(c); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci fail: 44262306a36Sopenharmony_ci iget_failed(inode); 44362306a36Sopenharmony_ci return ret; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, 44862306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct jffs2_inode_info *f, *dir_f; 45162306a36Sopenharmony_ci struct jffs2_sb_info *c; 45262306a36Sopenharmony_ci struct inode *inode; 45362306a36Sopenharmony_ci struct jffs2_raw_inode *ri; 45462306a36Sopenharmony_ci struct jffs2_raw_dirent *rd; 45562306a36Sopenharmony_ci struct jffs2_full_dnode *fn; 45662306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 45762306a36Sopenharmony_ci int namelen; 45862306a36Sopenharmony_ci uint32_t alloclen; 45962306a36Sopenharmony_ci int ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci mode |= S_IFDIR; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ri = jffs2_alloc_raw_inode(); 46462306a36Sopenharmony_ci if (!ri) 46562306a36Sopenharmony_ci return -ENOMEM; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci c = JFFS2_SB_INFO(dir_i->i_sb); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Try to reserve enough space for both node and dirent. 47062306a36Sopenharmony_ci * Just the node will do for now, though 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci namelen = dentry->d_name.len; 47362306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, 47462306a36Sopenharmony_ci JFFS2_SUMMARY_INODE_SIZE); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ret) { 47762306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 47862306a36Sopenharmony_ci return ret; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci inode = jffs2_new_inode(dir_i, mode, ri); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (IS_ERR(inode)) { 48462306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 48562306a36Sopenharmony_ci jffs2_complete_reservation(c); 48662306a36Sopenharmony_ci return PTR_ERR(inode); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci inode->i_op = &jffs2_dir_inode_operations; 49062306a36Sopenharmony_ci inode->i_fop = &jffs2_dir_operations; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Directories get nlink 2 at start */ 49562306a36Sopenharmony_ci set_nlink(inode, 2); 49662306a36Sopenharmony_ci /* but ic->pino_nlink is the parent ino# */ 49762306a36Sopenharmony_ci f->inocache->pino_nlink = dir_i->i_ino; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ri->data_crc = cpu_to_je32(0); 50062306a36Sopenharmony_ci ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (IS_ERR(fn)) { 50762306a36Sopenharmony_ci /* Eeek. Wave bye bye */ 50862306a36Sopenharmony_ci mutex_unlock(&f->sem); 50962306a36Sopenharmony_ci jffs2_complete_reservation(c); 51062306a36Sopenharmony_ci ret = PTR_ERR(fn); 51162306a36Sopenharmony_ci goto fail; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci /* No data here. Only a metadata node, which will be 51462306a36Sopenharmony_ci obsoleted by the first data write 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci f->metadata = fn; 51762306a36Sopenharmony_ci mutex_unlock(&f->sem); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci jffs2_complete_reservation(c); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ret = jffs2_init_security(inode, dir_i, &dentry->d_name); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci goto fail; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = jffs2_init_acl_post(inode); 52662306a36Sopenharmony_ci if (ret) 52762306a36Sopenharmony_ci goto fail; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, 53062306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci goto fail; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci rd = jffs2_alloc_raw_dirent(); 53562306a36Sopenharmony_ci if (!rd) { 53662306a36Sopenharmony_ci /* Argh. Now we treat it like a normal delete */ 53762306a36Sopenharmony_ci jffs2_complete_reservation(c); 53862306a36Sopenharmony_ci ret = -ENOMEM; 53962306a36Sopenharmony_ci goto fail; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci dir_f = JFFS2_INODE_INFO(dir_i); 54362306a36Sopenharmony_ci mutex_lock(&dir_f->sem); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 54662306a36Sopenharmony_ci rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 54762306a36Sopenharmony_ci rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 54862306a36Sopenharmony_ci rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci rd->pino = cpu_to_je32(dir_i->i_ino); 55162306a36Sopenharmony_ci rd->version = cpu_to_je32(++dir_f->highest_version); 55262306a36Sopenharmony_ci rd->ino = cpu_to_je32(inode->i_ino); 55362306a36Sopenharmony_ci rd->mctime = cpu_to_je32(JFFS2_NOW()); 55462306a36Sopenharmony_ci rd->nsize = namelen; 55562306a36Sopenharmony_ci rd->type = DT_DIR; 55662306a36Sopenharmony_ci rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 55762306a36Sopenharmony_ci rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (IS_ERR(fd)) { 56262306a36Sopenharmony_ci /* dirent failed to write. Delete the inode normally 56362306a36Sopenharmony_ci as if it were the final unlink() */ 56462306a36Sopenharmony_ci jffs2_complete_reservation(c); 56562306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 56662306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 56762306a36Sopenharmony_ci ret = PTR_ERR(fd); 56862306a36Sopenharmony_ci goto fail; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, 57262306a36Sopenharmony_ci ITIME(je32_to_cpu(rd->mctime))); 57362306a36Sopenharmony_ci inc_nlink(dir_i); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Link the fd into the inode's list, obsoleting an old 57862306a36Sopenharmony_ci one if necessary. */ 57962306a36Sopenharmony_ci jffs2_add_fd_to_list(c, fd, &dir_f->dents); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 58262306a36Sopenharmony_ci jffs2_complete_reservation(c); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci fail: 58862306a36Sopenharmony_ci iget_failed(inode); 58962306a36Sopenharmony_ci return ret; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); 59562306a36Sopenharmony_ci struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); 59662306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry)); 59762306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 59862306a36Sopenharmony_ci int ret; 59962306a36Sopenharmony_ci uint32_t now = JFFS2_NOW(); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci mutex_lock(&f->sem); 60262306a36Sopenharmony_ci for (fd = f->dents ; fd; fd = fd->next) { 60362306a36Sopenharmony_ci if (fd->ino) { 60462306a36Sopenharmony_ci mutex_unlock(&f->sem); 60562306a36Sopenharmony_ci return -ENOTEMPTY; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci mutex_unlock(&f->sem); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 61162306a36Sopenharmony_ci dentry->d_name.len, f, now); 61262306a36Sopenharmony_ci if (!ret) { 61362306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, ITIME(now)); 61462306a36Sopenharmony_ci clear_nlink(d_inode(dentry)); 61562306a36Sopenharmony_ci drop_nlink(dir_i); 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci return ret; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, 62162306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t rdev) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct jffs2_inode_info *f, *dir_f; 62462306a36Sopenharmony_ci struct jffs2_sb_info *c; 62562306a36Sopenharmony_ci struct inode *inode; 62662306a36Sopenharmony_ci struct jffs2_raw_inode *ri; 62762306a36Sopenharmony_ci struct jffs2_raw_dirent *rd; 62862306a36Sopenharmony_ci struct jffs2_full_dnode *fn; 62962306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 63062306a36Sopenharmony_ci int namelen; 63162306a36Sopenharmony_ci union jffs2_device_node dev; 63262306a36Sopenharmony_ci int devlen = 0; 63362306a36Sopenharmony_ci uint32_t alloclen; 63462306a36Sopenharmony_ci int ret; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ri = jffs2_alloc_raw_inode(); 63762306a36Sopenharmony_ci if (!ri) 63862306a36Sopenharmony_ci return -ENOMEM; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci c = JFFS2_SB_INFO(dir_i->i_sb); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (S_ISBLK(mode) || S_ISCHR(mode)) 64362306a36Sopenharmony_ci devlen = jffs2_encode_dev(&dev, rdev); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Try to reserve enough space for both node and dirent. 64662306a36Sopenharmony_ci * Just the node will do for now, though 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci namelen = dentry->d_name.len; 64962306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen, 65062306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (ret) { 65362306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 65462306a36Sopenharmony_ci return ret; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci inode = jffs2_new_inode(dir_i, mode, ri); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (IS_ERR(inode)) { 66062306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 66162306a36Sopenharmony_ci jffs2_complete_reservation(c); 66262306a36Sopenharmony_ci return PTR_ERR(inode); 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci inode->i_op = &jffs2_file_inode_operations; 66562306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ri->dsize = ri->csize = cpu_to_je32(devlen); 67062306a36Sopenharmony_ci ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); 67162306a36Sopenharmony_ci ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci ri->compr = JFFS2_COMPR_NONE; 67462306a36Sopenharmony_ci ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); 67562306a36Sopenharmony_ci ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (IS_ERR(fn)) { 68262306a36Sopenharmony_ci /* Eeek. Wave bye bye */ 68362306a36Sopenharmony_ci mutex_unlock(&f->sem); 68462306a36Sopenharmony_ci jffs2_complete_reservation(c); 68562306a36Sopenharmony_ci ret = PTR_ERR(fn); 68662306a36Sopenharmony_ci goto fail; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci /* No data here. Only a metadata node, which will be 68962306a36Sopenharmony_ci obsoleted by the first data write 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci f->metadata = fn; 69262306a36Sopenharmony_ci mutex_unlock(&f->sem); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci jffs2_complete_reservation(c); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci ret = jffs2_init_security(inode, dir_i, &dentry->d_name); 69762306a36Sopenharmony_ci if (ret) 69862306a36Sopenharmony_ci goto fail; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci ret = jffs2_init_acl_post(inode); 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci goto fail; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, 70562306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 70662306a36Sopenharmony_ci if (ret) 70762306a36Sopenharmony_ci goto fail; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci rd = jffs2_alloc_raw_dirent(); 71062306a36Sopenharmony_ci if (!rd) { 71162306a36Sopenharmony_ci /* Argh. Now we treat it like a normal delete */ 71262306a36Sopenharmony_ci jffs2_complete_reservation(c); 71362306a36Sopenharmony_ci ret = -ENOMEM; 71462306a36Sopenharmony_ci goto fail; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci dir_f = JFFS2_INODE_INFO(dir_i); 71862306a36Sopenharmony_ci mutex_lock(&dir_f->sem); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 72162306a36Sopenharmony_ci rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 72262306a36Sopenharmony_ci rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 72362306a36Sopenharmony_ci rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci rd->pino = cpu_to_je32(dir_i->i_ino); 72662306a36Sopenharmony_ci rd->version = cpu_to_je32(++dir_f->highest_version); 72762306a36Sopenharmony_ci rd->ino = cpu_to_je32(inode->i_ino); 72862306a36Sopenharmony_ci rd->mctime = cpu_to_je32(JFFS2_NOW()); 72962306a36Sopenharmony_ci rd->nsize = namelen; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* XXX: This is ugly. */ 73262306a36Sopenharmony_ci rd->type = (mode & S_IFMT) >> 12; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 73562306a36Sopenharmony_ci rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (IS_ERR(fd)) { 74062306a36Sopenharmony_ci /* dirent failed to write. Delete the inode normally 74162306a36Sopenharmony_ci as if it were the final unlink() */ 74262306a36Sopenharmony_ci jffs2_complete_reservation(c); 74362306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 74462306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 74562306a36Sopenharmony_ci ret = PTR_ERR(fd); 74662306a36Sopenharmony_ci goto fail; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci dir_i->i_mtime = inode_set_ctime_to_ts(dir_i, 75062306a36Sopenharmony_ci ITIME(je32_to_cpu(rd->mctime))); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci jffs2_free_raw_dirent(rd); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Link the fd into the inode's list, obsoleting an old 75562306a36Sopenharmony_ci one if necessary. */ 75662306a36Sopenharmony_ci jffs2_add_fd_to_list(c, fd, &dir_f->dents); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci mutex_unlock(&dir_f->sem); 75962306a36Sopenharmony_ci jffs2_complete_reservation(c); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci fail: 76562306a36Sopenharmony_ci iget_failed(inode); 76662306a36Sopenharmony_ci return ret; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int jffs2_rename (struct mnt_idmap *idmap, 77062306a36Sopenharmony_ci struct inode *old_dir_i, struct dentry *old_dentry, 77162306a36Sopenharmony_ci struct inode *new_dir_i, struct dentry *new_dentry, 77262306a36Sopenharmony_ci unsigned int flags) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci int ret; 77562306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); 77662306a36Sopenharmony_ci struct jffs2_inode_info *victim_f = NULL; 77762306a36Sopenharmony_ci uint8_t type; 77862306a36Sopenharmony_ci uint32_t now; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (flags & ~RENAME_NOREPLACE) 78162306a36Sopenharmony_ci return -EINVAL; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* The VFS will check for us and prevent trying to rename a 78462306a36Sopenharmony_ci * file over a directory and vice versa, but if it's a directory, 78562306a36Sopenharmony_ci * the VFS can't check whether the victim is empty. The filesystem 78662306a36Sopenharmony_ci * needs to do that for itself. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci if (d_really_is_positive(new_dentry)) { 78962306a36Sopenharmony_ci victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); 79062306a36Sopenharmony_ci if (d_is_dir(new_dentry)) { 79162306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci mutex_lock(&victim_f->sem); 79462306a36Sopenharmony_ci for (fd = victim_f->dents; fd; fd = fd->next) { 79562306a36Sopenharmony_ci if (fd->ino) { 79662306a36Sopenharmony_ci mutex_unlock(&victim_f->sem); 79762306a36Sopenharmony_ci return -ENOTEMPTY; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci mutex_unlock(&victim_f->sem); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* XXX: We probably ought to alloc enough space for 80562306a36Sopenharmony_ci both nodes at the same time. Writing the new link, 80662306a36Sopenharmony_ci then getting -ENOSPC, is quite bad :) 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Make a hard link */ 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* XXX: This is ugly */ 81262306a36Sopenharmony_ci type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; 81362306a36Sopenharmony_ci if (!type) type = DT_REG; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci now = JFFS2_NOW(); 81662306a36Sopenharmony_ci ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 81762306a36Sopenharmony_ci d_inode(old_dentry)->i_ino, type, 81862306a36Sopenharmony_ci new_dentry->d_name.name, new_dentry->d_name.len, now); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (ret) 82162306a36Sopenharmony_ci return ret; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (victim_f) { 82462306a36Sopenharmony_ci /* There was a victim. Kill it off nicely */ 82562306a36Sopenharmony_ci if (d_is_dir(new_dentry)) 82662306a36Sopenharmony_ci clear_nlink(d_inode(new_dentry)); 82762306a36Sopenharmony_ci else 82862306a36Sopenharmony_ci drop_nlink(d_inode(new_dentry)); 82962306a36Sopenharmony_ci /* Don't oops if the victim was a dirent pointing to an 83062306a36Sopenharmony_ci inode which didn't exist. */ 83162306a36Sopenharmony_ci if (victim_f->inocache) { 83262306a36Sopenharmony_ci mutex_lock(&victim_f->sem); 83362306a36Sopenharmony_ci if (d_is_dir(new_dentry)) 83462306a36Sopenharmony_ci victim_f->inocache->pino_nlink = 0; 83562306a36Sopenharmony_ci else 83662306a36Sopenharmony_ci victim_f->inocache->pino_nlink--; 83762306a36Sopenharmony_ci mutex_unlock(&victim_f->sem); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* If it was a directory we moved, and there was no victim, 84262306a36Sopenharmony_ci increase i_nlink on its new parent */ 84362306a36Sopenharmony_ci if (d_is_dir(old_dentry) && !victim_f) 84462306a36Sopenharmony_ci inc_nlink(new_dir_i); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* Unlink the original */ 84762306a36Sopenharmony_ci ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 84862306a36Sopenharmony_ci old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* We don't touch inode->i_nlink */ 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (ret) { 85362306a36Sopenharmony_ci /* Oh shit. We really ought to make a single node which can do both atomically */ 85462306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); 85562306a36Sopenharmony_ci mutex_lock(&f->sem); 85662306a36Sopenharmony_ci inc_nlink(d_inode(old_dentry)); 85762306a36Sopenharmony_ci if (f->inocache && !d_is_dir(old_dentry)) 85862306a36Sopenharmony_ci f->inocache->pino_nlink++; 85962306a36Sopenharmony_ci mutex_unlock(&f->sem); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", 86262306a36Sopenharmony_ci __func__, ret); 86362306a36Sopenharmony_ci /* 86462306a36Sopenharmony_ci * We can't keep the target in dcache after that. 86562306a36Sopenharmony_ci * For one thing, we can't afford dentry aliases for directories. 86662306a36Sopenharmony_ci * For another, if there was a victim, we _can't_ set new inode 86762306a36Sopenharmony_ci * for that sucker and we have to trigger mount eviction - the 86862306a36Sopenharmony_ci * caller won't do it on its own since we are returning an error. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci d_invalidate(new_dentry); 87162306a36Sopenharmony_ci new_dir_i->i_mtime = inode_set_ctime_to_ts(new_dir_i, 87262306a36Sopenharmony_ci ITIME(now)); 87362306a36Sopenharmony_ci return ret; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (d_is_dir(old_dentry)) 87762306a36Sopenharmony_ci drop_nlink(old_dir_i); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci old_dir_i->i_mtime = inode_set_ctime_to_ts(old_dir_i, ITIME(now)); 88062306a36Sopenharmony_ci new_dir_i->i_mtime = inode_set_ctime_to_ts(new_dir_i, ITIME(now)); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 885