11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 10*2b79adccSArtem B. Bityutskiy * $Id: dir.c,v 1.87 2005/07/17 11:13:46 dedekind Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/sched.h> 171da177e4SLinus Torvalds #include <linux/fs.h> 181da177e4SLinus Torvalds #include <linux/crc32.h> 191da177e4SLinus Torvalds #include <linux/jffs2.h> 201da177e4SLinus Torvalds #include <linux/jffs2_fs_i.h> 211da177e4SLinus Torvalds #include <linux/jffs2_fs_sb.h> 221da177e4SLinus Torvalds #include <linux/time.h> 231da177e4SLinus Torvalds #include "nodelist.h" 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds static int jffs2_readdir (struct file *, void *, filldir_t); 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds static int jffs2_create (struct inode *,struct dentry *,int, 281da177e4SLinus Torvalds struct nameidata *); 291da177e4SLinus Torvalds static struct dentry *jffs2_lookup (struct inode *,struct dentry *, 301da177e4SLinus Torvalds struct nameidata *); 311da177e4SLinus Torvalds static int jffs2_link (struct dentry *,struct inode *,struct dentry *); 321da177e4SLinus Torvalds static int jffs2_unlink (struct inode *,struct dentry *); 331da177e4SLinus Torvalds static int jffs2_symlink (struct inode *,struct dentry *,const char *); 341da177e4SLinus Torvalds static int jffs2_mkdir (struct inode *,struct dentry *,int); 351da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *,struct dentry *); 36265489f0SDavid Woodhouse static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); 371da177e4SLinus Torvalds static int jffs2_rename (struct inode *, struct dentry *, 381da177e4SLinus Torvalds struct inode *, struct dentry *); 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds struct file_operations jffs2_dir_operations = 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds .read = generic_read_dir, 431da177e4SLinus Torvalds .readdir = jffs2_readdir, 441da177e4SLinus Torvalds .ioctl = jffs2_ioctl, 451da177e4SLinus Torvalds .fsync = jffs2_fsync 461da177e4SLinus Torvalds }; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds struct inode_operations jffs2_dir_inode_operations = 501da177e4SLinus Torvalds { 51265489f0SDavid Woodhouse .create = jffs2_create, 52265489f0SDavid Woodhouse .lookup = jffs2_lookup, 531da177e4SLinus Torvalds .link = jffs2_link, 541da177e4SLinus Torvalds .unlink = jffs2_unlink, 551da177e4SLinus Torvalds .symlink = jffs2_symlink, 561da177e4SLinus Torvalds .mkdir = jffs2_mkdir, 571da177e4SLinus Torvalds .rmdir = jffs2_rmdir, 581da177e4SLinus Torvalds .mknod = jffs2_mknod, 591da177e4SLinus Torvalds .rename = jffs2_rename, 601da177e4SLinus Torvalds .setattr = jffs2_setattr, 611da177e4SLinus Torvalds }; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /***********************************************************************/ 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /* We keep the dirent list sorted in increasing order of name hash, 671da177e4SLinus Torvalds and we use the same hash function as the dentries. Makes this 681da177e4SLinus Torvalds nice and simple 691da177e4SLinus Torvalds */ 701da177e4SLinus Torvalds static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, 711da177e4SLinus Torvalds struct nameidata *nd) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds struct jffs2_inode_info *dir_f; 741da177e4SLinus Torvalds struct jffs2_sb_info *c; 751da177e4SLinus Torvalds struct jffs2_full_dirent *fd = NULL, *fd_list; 761da177e4SLinus Torvalds uint32_t ino = 0; 771da177e4SLinus Torvalds struct inode *inode = NULL; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_lookup()\n")); 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds dir_f = JFFS2_INODE_INFO(dir_i); 821da177e4SLinus Torvalds c = JFFS2_SB_INFO(dir_i->i_sb); 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds down(&dir_f->sem); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ 871da177e4SLinus Torvalds for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { 881da177e4SLinus Torvalds if (fd_list->nhash == target->d_name.hash && 891da177e4SLinus Torvalds (!fd || fd_list->version > fd->version) && 901da177e4SLinus Torvalds strlen(fd_list->name) == target->d_name.len && 911da177e4SLinus Torvalds !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { 921da177e4SLinus Torvalds fd = fd_list; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds if (fd) 961da177e4SLinus Torvalds ino = fd->ino; 971da177e4SLinus Torvalds up(&dir_f->sem); 981da177e4SLinus Torvalds if (ino) { 991da177e4SLinus Torvalds inode = iget(dir_i->i_sb, ino); 1001da177e4SLinus Torvalds if (!inode) { 1011da177e4SLinus Torvalds printk(KERN_WARNING "iget() failed for ino #%u\n", ino); 1021da177e4SLinus Torvalds return (ERR_PTR(-EIO)); 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds d_add(target, inode); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds return NULL; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /***********************************************************************/ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) 1151da177e4SLinus Torvalds { 1161da177e4SLinus Torvalds struct jffs2_inode_info *f; 1171da177e4SLinus Torvalds struct jffs2_sb_info *c; 1181da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 1191da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 1201da177e4SLinus Torvalds unsigned long offset, curofs; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_dentry->d_inode->i_ino)); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds f = JFFS2_INODE_INFO(inode); 1251da177e4SLinus Torvalds c = JFFS2_SB_INFO(inode->i_sb); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds offset = filp->f_pos; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if (offset == 0) { 1301da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino)); 1311da177e4SLinus Torvalds if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) 1321da177e4SLinus Torvalds goto out; 1331da177e4SLinus Torvalds offset++; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds if (offset == 1) { 1361da177e4SLinus Torvalds unsigned long pino = parent_ino(filp->f_dentry); 1371da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino)); 1381da177e4SLinus Torvalds if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0) 1391da177e4SLinus Torvalds goto out; 1401da177e4SLinus Torvalds offset++; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds curofs=1; 1441da177e4SLinus Torvalds down(&f->sem); 1451da177e4SLinus Torvalds for (fd = f->dents; fd; fd = fd->next) { 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds curofs++; 1481da177e4SLinus Torvalds /* First loop: curofs = 2; offset = 2 */ 1491da177e4SLinus Torvalds if (curofs < offset) { 1501da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", 1511da177e4SLinus Torvalds fd->name, fd->ino, fd->type, curofs, offset)); 1521da177e4SLinus Torvalds continue; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds if (!fd->ino) { 1551da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name)); 1561da177e4SLinus Torvalds offset++; 1571da177e4SLinus Torvalds continue; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, fd->name, fd->ino, fd->type)); 1601da177e4SLinus Torvalds if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0) 1611da177e4SLinus Torvalds break; 1621da177e4SLinus Torvalds offset++; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds up(&f->sem); 1651da177e4SLinus Torvalds out: 1661da177e4SLinus Torvalds filp->f_pos = offset; 1671da177e4SLinus Torvalds return 0; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /***********************************************************************/ 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, 1741da177e4SLinus Torvalds struct nameidata *nd) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 1771da177e4SLinus Torvalds struct jffs2_inode_info *f, *dir_f; 1781da177e4SLinus Torvalds struct jffs2_sb_info *c; 1791da177e4SLinus Torvalds struct inode *inode; 1801da177e4SLinus Torvalds int ret; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 1831da177e4SLinus Torvalds if (!ri) 1841da177e4SLinus Torvalds return -ENOMEM; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds c = JFFS2_SB_INFO(dir_i->i_sb); 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_create()\n")); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds inode = jffs2_new_inode(dir_i, mode, ri); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds if (IS_ERR(inode)) { 1931da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); 1941da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 1951da177e4SLinus Torvalds return PTR_ERR(inode); 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds inode->i_op = &jffs2_file_inode_operations; 1991da177e4SLinus Torvalds inode->i_fop = &jffs2_file_operations; 2001da177e4SLinus Torvalds inode->i_mapping->a_ops = &jffs2_file_address_operations; 2011da177e4SLinus Torvalds inode->i_mapping->nrpages = 0; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds f = JFFS2_INODE_INFO(inode); 2041da177e4SLinus Torvalds dir_f = JFFS2_INODE_INFO(dir_i); 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds ret = jffs2_do_create(c, dir_f, f, ri, 2071da177e4SLinus Torvalds dentry->d_name.name, dentry->d_name.len); 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds if (ret) { 2101da177e4SLinus Torvalds make_bad_inode(inode); 2111da177e4SLinus Torvalds iput(inode); 2121da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 2131da177e4SLinus Torvalds return ret; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 2191da177e4SLinus Torvalds d_instantiate(dentry, inode); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", 2221da177e4SLinus Torvalds inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /***********************************************************************/ 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); 2321da177e4SLinus Torvalds struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); 2331da177e4SLinus Torvalds struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); 2341da177e4SLinus Torvalds int ret; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 2371da177e4SLinus Torvalds dentry->d_name.len, dead_f); 2381da177e4SLinus Torvalds if (dead_f->inocache) 2391da177e4SLinus Torvalds dentry->d_inode->i_nlink = dead_f->inocache->nlink; 2401da177e4SLinus Torvalds return ret; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds /***********************************************************************/ 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) 2461da177e4SLinus Torvalds { 2471da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); 2481da177e4SLinus Torvalds struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); 2491da177e4SLinus Torvalds struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); 2501da177e4SLinus Torvalds int ret; 2511da177e4SLinus Torvalds uint8_t type; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* Don't let people make hard links to bad inodes. */ 2541da177e4SLinus Torvalds if (!f->inocache) 2551da177e4SLinus Torvalds return -EIO; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds if (S_ISDIR(old_dentry->d_inode->i_mode)) 2581da177e4SLinus Torvalds return -EPERM; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* XXX: This is ugly */ 2611da177e4SLinus Torvalds type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; 2621da177e4SLinus Torvalds if (!type) type = DT_REG; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds if (!ret) { 2671da177e4SLinus Torvalds down(&f->sem); 2681da177e4SLinus Torvalds old_dentry->d_inode->i_nlink = ++f->inocache->nlink; 2691da177e4SLinus Torvalds up(&f->sem); 2701da177e4SLinus Torvalds d_instantiate(dentry, old_dentry->d_inode); 2711da177e4SLinus Torvalds atomic_inc(&old_dentry->d_inode->i_count); 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds return ret; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /***********************************************************************/ 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds struct jffs2_inode_info *f, *dir_f; 2811da177e4SLinus Torvalds struct jffs2_sb_info *c; 2821da177e4SLinus Torvalds struct inode *inode; 2831da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 2841da177e4SLinus Torvalds struct jffs2_raw_dirent *rd; 2851da177e4SLinus Torvalds struct jffs2_full_dnode *fn; 2861da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 2871da177e4SLinus Torvalds int namelen; 2881da177e4SLinus Torvalds uint32_t alloclen, phys_ofs; 28932f1a95dSArtem B. Bityuckiy int ret, targetlen = strlen(target); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* FIXME: If you care. We'd need to use frags for the target 2921da177e4SLinus Torvalds if it grows much more than this */ 29332f1a95dSArtem B. Bityuckiy if (targetlen > 254) 2941da177e4SLinus Torvalds return -EINVAL; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (!ri) 2991da177e4SLinus Torvalds return -ENOMEM; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds c = JFFS2_SB_INFO(dir_i->i_sb); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* Try to reserve enough space for both node and dirent. 3041da177e4SLinus Torvalds * Just the node will do for now, though 3051da177e4SLinus Torvalds */ 3061da177e4SLinus Torvalds namelen = dentry->d_name.len; 30732f1a95dSArtem B. Bityuckiy ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds if (ret) { 3101da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 3111da177e4SLinus Torvalds return ret; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds if (IS_ERR(inode)) { 3171da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 3181da177e4SLinus Torvalds jffs2_complete_reservation(c); 3191da177e4SLinus Torvalds return PTR_ERR(inode); 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds inode->i_op = &jffs2_symlink_inode_operations; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds f = JFFS2_INODE_INFO(inode); 3251da177e4SLinus Torvalds 32632f1a95dSArtem B. Bityuckiy inode->i_size = targetlen; 3271da177e4SLinus Torvalds ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); 3281da177e4SLinus Torvalds ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); 3291da177e4SLinus Torvalds ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds ri->compr = JFFS2_COMPR_NONE; 33232f1a95dSArtem B. Bityuckiy ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); 3331da177e4SLinus Torvalds ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 3341da177e4SLinus Torvalds 33532f1a95dSArtem B. Bityuckiy fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (IS_ERR(fn)) { 3401da177e4SLinus Torvalds /* Eeek. Wave bye bye */ 3411da177e4SLinus Torvalds up(&f->sem); 3421da177e4SLinus Torvalds jffs2_complete_reservation(c); 3431da177e4SLinus Torvalds jffs2_clear_inode(inode); 3441da177e4SLinus Torvalds return PTR_ERR(fn); 3451da177e4SLinus Torvalds } 34632f1a95dSArtem B. Bityuckiy 347*2b79adccSArtem B. Bityutskiy /* We use f->target field to store the target path. */ 348*2b79adccSArtem B. Bityutskiy f->target = kmalloc(targetlen + 1, GFP_KERNEL); 349*2b79adccSArtem B. Bityutskiy if (!f->target) { 35032f1a95dSArtem B. Bityuckiy printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); 35132f1a95dSArtem B. Bityuckiy up(&f->sem); 35232f1a95dSArtem B. Bityuckiy jffs2_complete_reservation(c); 35332f1a95dSArtem B. Bityuckiy jffs2_clear_inode(inode); 35432f1a95dSArtem B. Bityuckiy return -ENOMEM; 35532f1a95dSArtem B. Bityuckiy } 35632f1a95dSArtem B. Bityuckiy 357*2b79adccSArtem B. Bityutskiy memcpy(f->target, target, targetlen + 1); 358*2b79adccSArtem B. Bityutskiy D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); 35932f1a95dSArtem B. Bityuckiy 3601da177e4SLinus Torvalds /* No data here. Only a metadata node, which will be 3611da177e4SLinus Torvalds obsoleted by the first data write 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds f->metadata = fn; 3641da177e4SLinus Torvalds up(&f->sem); 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds jffs2_complete_reservation(c); 3671da177e4SLinus Torvalds ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 3681da177e4SLinus Torvalds if (ret) { 3691da177e4SLinus Torvalds /* Eep. */ 3701da177e4SLinus Torvalds jffs2_clear_inode(inode); 3711da177e4SLinus Torvalds return ret; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds rd = jffs2_alloc_raw_dirent(); 3751da177e4SLinus Torvalds if (!rd) { 3761da177e4SLinus Torvalds /* Argh. Now we treat it like a normal delete */ 3771da177e4SLinus Torvalds jffs2_complete_reservation(c); 3781da177e4SLinus Torvalds jffs2_clear_inode(inode); 3791da177e4SLinus Torvalds return -ENOMEM; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds dir_f = JFFS2_INODE_INFO(dir_i); 3831da177e4SLinus Torvalds down(&dir_f->sem); 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 3861da177e4SLinus Torvalds rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 3871da177e4SLinus Torvalds rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 3881da177e4SLinus Torvalds rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds rd->pino = cpu_to_je32(dir_i->i_ino); 3911da177e4SLinus Torvalds rd->version = cpu_to_je32(++dir_f->highest_version); 3921da177e4SLinus Torvalds rd->ino = cpu_to_je32(inode->i_ino); 3931da177e4SLinus Torvalds rd->mctime = cpu_to_je32(get_seconds()); 3941da177e4SLinus Torvalds rd->nsize = namelen; 3951da177e4SLinus Torvalds rd->type = DT_LNK; 3961da177e4SLinus Torvalds rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 3971da177e4SLinus Torvalds rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds if (IS_ERR(fd)) { 4021da177e4SLinus Torvalds /* dirent failed to write. Delete the inode normally 4031da177e4SLinus Torvalds as if it were the final unlink() */ 4041da177e4SLinus Torvalds jffs2_complete_reservation(c); 4051da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 4061da177e4SLinus Torvalds up(&dir_f->sem); 4071da177e4SLinus Torvalds jffs2_clear_inode(inode); 4081da177e4SLinus Torvalds return PTR_ERR(fd); 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* Link the fd into the inode's list, obsoleting an old 4161da177e4SLinus Torvalds one if necessary. */ 4171da177e4SLinus Torvalds jffs2_add_fd_to_list(c, fd, &dir_f->dents); 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds up(&dir_f->sem); 4201da177e4SLinus Torvalds jffs2_complete_reservation(c); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds d_instantiate(dentry, inode); 4231da177e4SLinus Torvalds return 0; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) 4281da177e4SLinus Torvalds { 4291da177e4SLinus Torvalds struct jffs2_inode_info *f, *dir_f; 4301da177e4SLinus Torvalds struct jffs2_sb_info *c; 4311da177e4SLinus Torvalds struct inode *inode; 4321da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 4331da177e4SLinus Torvalds struct jffs2_raw_dirent *rd; 4341da177e4SLinus Torvalds struct jffs2_full_dnode *fn; 4351da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 4361da177e4SLinus Torvalds int namelen; 4371da177e4SLinus Torvalds uint32_t alloclen, phys_ofs; 4381da177e4SLinus Torvalds int ret; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds mode |= S_IFDIR; 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 4431da177e4SLinus Torvalds if (!ri) 4441da177e4SLinus Torvalds return -ENOMEM; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds c = JFFS2_SB_INFO(dir_i->i_sb); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds /* Try to reserve enough space for both node and dirent. 4491da177e4SLinus Torvalds * Just the node will do for now, though 4501da177e4SLinus Torvalds */ 4511da177e4SLinus Torvalds namelen = dentry->d_name.len; 4521da177e4SLinus Torvalds ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds if (ret) { 4551da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 4561da177e4SLinus Torvalds return ret; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds inode = jffs2_new_inode(dir_i, mode, ri); 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds if (IS_ERR(inode)) { 4621da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 4631da177e4SLinus Torvalds jffs2_complete_reservation(c); 4641da177e4SLinus Torvalds return PTR_ERR(inode); 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds inode->i_op = &jffs2_dir_inode_operations; 4681da177e4SLinus Torvalds inode->i_fop = &jffs2_dir_operations; 4691da177e4SLinus Torvalds /* Directories get nlink 2 at start */ 4701da177e4SLinus Torvalds inode->i_nlink = 2; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds f = JFFS2_INODE_INFO(inode); 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds ri->data_crc = cpu_to_je32(0); 4751da177e4SLinus Torvalds ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if (IS_ERR(fn)) { 4821da177e4SLinus Torvalds /* Eeek. Wave bye bye */ 4831da177e4SLinus Torvalds up(&f->sem); 4841da177e4SLinus Torvalds jffs2_complete_reservation(c); 4851da177e4SLinus Torvalds jffs2_clear_inode(inode); 4861da177e4SLinus Torvalds return PTR_ERR(fn); 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds /* No data here. Only a metadata node, which will be 4891da177e4SLinus Torvalds obsoleted by the first data write 4901da177e4SLinus Torvalds */ 4911da177e4SLinus Torvalds f->metadata = fn; 4921da177e4SLinus Torvalds up(&f->sem); 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds jffs2_complete_reservation(c); 4951da177e4SLinus Torvalds ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 4961da177e4SLinus Torvalds if (ret) { 4971da177e4SLinus Torvalds /* Eep. */ 4981da177e4SLinus Torvalds jffs2_clear_inode(inode); 4991da177e4SLinus Torvalds return ret; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds rd = jffs2_alloc_raw_dirent(); 5031da177e4SLinus Torvalds if (!rd) { 5041da177e4SLinus Torvalds /* Argh. Now we treat it like a normal delete */ 5051da177e4SLinus Torvalds jffs2_complete_reservation(c); 5061da177e4SLinus Torvalds jffs2_clear_inode(inode); 5071da177e4SLinus Torvalds return -ENOMEM; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds dir_f = JFFS2_INODE_INFO(dir_i); 5111da177e4SLinus Torvalds down(&dir_f->sem); 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 5141da177e4SLinus Torvalds rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 5151da177e4SLinus Torvalds rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 5161da177e4SLinus Torvalds rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds rd->pino = cpu_to_je32(dir_i->i_ino); 5191da177e4SLinus Torvalds rd->version = cpu_to_je32(++dir_f->highest_version); 5201da177e4SLinus Torvalds rd->ino = cpu_to_je32(inode->i_ino); 5211da177e4SLinus Torvalds rd->mctime = cpu_to_je32(get_seconds()); 5221da177e4SLinus Torvalds rd->nsize = namelen; 5231da177e4SLinus Torvalds rd->type = DT_DIR; 5241da177e4SLinus Torvalds rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 5251da177e4SLinus Torvalds rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds if (IS_ERR(fd)) { 5301da177e4SLinus Torvalds /* dirent failed to write. Delete the inode normally 5311da177e4SLinus Torvalds as if it were the final unlink() */ 5321da177e4SLinus Torvalds jffs2_complete_reservation(c); 5331da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 5341da177e4SLinus Torvalds up(&dir_f->sem); 5351da177e4SLinus Torvalds jffs2_clear_inode(inode); 5361da177e4SLinus Torvalds return PTR_ERR(fd); 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); 5401da177e4SLinus Torvalds dir_i->i_nlink++; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds /* Link the fd into the inode's list, obsoleting an old 5451da177e4SLinus Torvalds one if necessary. */ 5461da177e4SLinus Torvalds jffs2_add_fd_to_list(c, fd, &dir_f->dents); 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds up(&dir_f->sem); 5491da177e4SLinus Torvalds jffs2_complete_reservation(c); 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds d_instantiate(dentry, inode); 5521da177e4SLinus Torvalds return 0; 5531da177e4SLinus Torvalds } 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) 5561da177e4SLinus Torvalds { 5571da177e4SLinus Torvalds struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); 5581da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 5591da177e4SLinus Torvalds int ret; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds for (fd = f->dents ; fd; fd = fd->next) { 5621da177e4SLinus Torvalds if (fd->ino) 5631da177e4SLinus Torvalds return -ENOTEMPTY; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds ret = jffs2_unlink(dir_i, dentry); 5661da177e4SLinus Torvalds if (!ret) 5671da177e4SLinus Torvalds dir_i->i_nlink--; 5681da177e4SLinus Torvalds return ret; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 571265489f0SDavid Woodhouse static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds struct jffs2_inode_info *f, *dir_f; 5741da177e4SLinus Torvalds struct jffs2_sb_info *c; 5751da177e4SLinus Torvalds struct inode *inode; 5761da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 5771da177e4SLinus Torvalds struct jffs2_raw_dirent *rd; 5781da177e4SLinus Torvalds struct jffs2_full_dnode *fn; 5791da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 5801da177e4SLinus Torvalds int namelen; 5811da177e4SLinus Torvalds jint16_t dev; 5821da177e4SLinus Torvalds int devlen = 0; 5831da177e4SLinus Torvalds uint32_t alloclen, phys_ofs; 5841da177e4SLinus Torvalds int ret; 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds if (!old_valid_dev(rdev)) 5871da177e4SLinus Torvalds return -EINVAL; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 5901da177e4SLinus Torvalds if (!ri) 5911da177e4SLinus Torvalds return -ENOMEM; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds c = JFFS2_SB_INFO(dir_i->i_sb); 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds if (S_ISBLK(mode) || S_ISCHR(mode)) { 5961da177e4SLinus Torvalds dev = cpu_to_je16(old_encode_dev(rdev)); 5971da177e4SLinus Torvalds devlen = sizeof(dev); 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds /* Try to reserve enough space for both node and dirent. 6011da177e4SLinus Torvalds * Just the node will do for now, though 6021da177e4SLinus Torvalds */ 6031da177e4SLinus Torvalds namelen = dentry->d_name.len; 6041da177e4SLinus Torvalds ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds if (ret) { 6071da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 6081da177e4SLinus Torvalds return ret; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds inode = jffs2_new_inode(dir_i, mode, ri); 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds if (IS_ERR(inode)) { 6141da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 6151da177e4SLinus Torvalds jffs2_complete_reservation(c); 6161da177e4SLinus Torvalds return PTR_ERR(inode); 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds inode->i_op = &jffs2_file_inode_operations; 6191da177e4SLinus Torvalds init_special_inode(inode, inode->i_mode, rdev); 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds f = JFFS2_INODE_INFO(inode); 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds ri->dsize = ri->csize = cpu_to_je32(devlen); 6241da177e4SLinus Torvalds ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); 6251da177e4SLinus Torvalds ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds ri->compr = JFFS2_COMPR_NONE; 6281da177e4SLinus Torvalds ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); 6291da177e4SLinus Torvalds ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds if (IS_ERR(fn)) { 6361da177e4SLinus Torvalds /* Eeek. Wave bye bye */ 6371da177e4SLinus Torvalds up(&f->sem); 6381da177e4SLinus Torvalds jffs2_complete_reservation(c); 6391da177e4SLinus Torvalds jffs2_clear_inode(inode); 6401da177e4SLinus Torvalds return PTR_ERR(fn); 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds /* No data here. Only a metadata node, which will be 6431da177e4SLinus Torvalds obsoleted by the first data write 6441da177e4SLinus Torvalds */ 6451da177e4SLinus Torvalds f->metadata = fn; 6461da177e4SLinus Torvalds up(&f->sem); 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds jffs2_complete_reservation(c); 6491da177e4SLinus Torvalds ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 6501da177e4SLinus Torvalds if (ret) { 6511da177e4SLinus Torvalds /* Eep. */ 6521da177e4SLinus Torvalds jffs2_clear_inode(inode); 6531da177e4SLinus Torvalds return ret; 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds rd = jffs2_alloc_raw_dirent(); 6571da177e4SLinus Torvalds if (!rd) { 6581da177e4SLinus Torvalds /* Argh. Now we treat it like a normal delete */ 6591da177e4SLinus Torvalds jffs2_complete_reservation(c); 6601da177e4SLinus Torvalds jffs2_clear_inode(inode); 6611da177e4SLinus Torvalds return -ENOMEM; 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds dir_f = JFFS2_INODE_INFO(dir_i); 6651da177e4SLinus Torvalds down(&dir_f->sem); 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 6681da177e4SLinus Torvalds rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 6691da177e4SLinus Torvalds rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); 6701da177e4SLinus Torvalds rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds rd->pino = cpu_to_je32(dir_i->i_ino); 6731da177e4SLinus Torvalds rd->version = cpu_to_je32(++dir_f->highest_version); 6741da177e4SLinus Torvalds rd->ino = cpu_to_je32(inode->i_ino); 6751da177e4SLinus Torvalds rd->mctime = cpu_to_je32(get_seconds()); 6761da177e4SLinus Torvalds rd->nsize = namelen; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds /* XXX: This is ugly. */ 6791da177e4SLinus Torvalds rd->type = (mode & S_IFMT) >> 12; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); 6821da177e4SLinus Torvalds rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds if (IS_ERR(fd)) { 6871da177e4SLinus Torvalds /* dirent failed to write. Delete the inode normally 6881da177e4SLinus Torvalds as if it were the final unlink() */ 6891da177e4SLinus Torvalds jffs2_complete_reservation(c); 6901da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 6911da177e4SLinus Torvalds up(&dir_f->sem); 6921da177e4SLinus Torvalds jffs2_clear_inode(inode); 6931da177e4SLinus Torvalds return PTR_ERR(fd); 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds jffs2_free_raw_dirent(rd); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds /* Link the fd into the inode's list, obsoleting an old 7011da177e4SLinus Torvalds one if necessary. */ 7021da177e4SLinus Torvalds jffs2_add_fd_to_list(c, fd, &dir_f->dents); 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds up(&dir_f->sem); 7051da177e4SLinus Torvalds jffs2_complete_reservation(c); 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds d_instantiate(dentry, inode); 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds return 0; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, 7131da177e4SLinus Torvalds struct inode *new_dir_i, struct dentry *new_dentry) 7141da177e4SLinus Torvalds { 7151da177e4SLinus Torvalds int ret; 7161da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); 7171da177e4SLinus Torvalds struct jffs2_inode_info *victim_f = NULL; 7181da177e4SLinus Torvalds uint8_t type; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds /* The VFS will check for us and prevent trying to rename a 7211da177e4SLinus Torvalds * file over a directory and vice versa, but if it's a directory, 7221da177e4SLinus Torvalds * the VFS can't check whether the victim is empty. The filesystem 7231da177e4SLinus Torvalds * needs to do that for itself. 7241da177e4SLinus Torvalds */ 7251da177e4SLinus Torvalds if (new_dentry->d_inode) { 7261da177e4SLinus Torvalds victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); 7271da177e4SLinus Torvalds if (S_ISDIR(new_dentry->d_inode->i_mode)) { 7281da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds down(&victim_f->sem); 7311da177e4SLinus Torvalds for (fd = victim_f->dents; fd; fd = fd->next) { 7321da177e4SLinus Torvalds if (fd->ino) { 7331da177e4SLinus Torvalds up(&victim_f->sem); 7341da177e4SLinus Torvalds return -ENOTEMPTY; 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds up(&victim_f->sem); 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds /* XXX: We probably ought to alloc enough space for 7421da177e4SLinus Torvalds both nodes at the same time. Writing the new link, 7431da177e4SLinus Torvalds then getting -ENOSPC, is quite bad :) 7441da177e4SLinus Torvalds */ 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds /* Make a hard link */ 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* XXX: This is ugly */ 7491da177e4SLinus Torvalds type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; 7501da177e4SLinus Torvalds if (!type) type = DT_REG; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 7531da177e4SLinus Torvalds old_dentry->d_inode->i_ino, type, 7541da177e4SLinus Torvalds new_dentry->d_name.name, new_dentry->d_name.len); 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds if (ret) 7571da177e4SLinus Torvalds return ret; 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds if (victim_f) { 7601da177e4SLinus Torvalds /* There was a victim. Kill it off nicely */ 7611da177e4SLinus Torvalds new_dentry->d_inode->i_nlink--; 7621da177e4SLinus Torvalds /* Don't oops if the victim was a dirent pointing to an 7631da177e4SLinus Torvalds inode which didn't exist. */ 7641da177e4SLinus Torvalds if (victim_f->inocache) { 7651da177e4SLinus Torvalds down(&victim_f->sem); 7661da177e4SLinus Torvalds victim_f->inocache->nlink--; 7671da177e4SLinus Torvalds up(&victim_f->sem); 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds /* If it was a directory we moved, and there was no victim, 7721da177e4SLinus Torvalds increase i_nlink on its new parent */ 7731da177e4SLinus Torvalds if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) 7741da177e4SLinus Torvalds new_dir_i->i_nlink++; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* Unlink the original */ 7771da177e4SLinus Torvalds ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 7781da177e4SLinus Torvalds old_dentry->d_name.name, old_dentry->d_name.len, NULL); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* We don't touch inode->i_nlink */ 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds if (ret) { 7831da177e4SLinus Torvalds /* Oh shit. We really ought to make a single node which can do both atomically */ 7841da177e4SLinus Torvalds struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); 7851da177e4SLinus Torvalds down(&f->sem); 7861da177e4SLinus Torvalds old_dentry->d_inode->i_nlink++; 7871da177e4SLinus Torvalds if (f->inocache) 7881da177e4SLinus Torvalds f->inocache->nlink++; 7891da177e4SLinus Torvalds up(&f->sem); 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); 7921da177e4SLinus Torvalds /* Might as well let the VFS know */ 7931da177e4SLinus Torvalds d_instantiate(new_dentry, old_dentry->d_inode); 7941da177e4SLinus Torvalds atomic_inc(&old_dentry->d_inode->i_count); 7951da177e4SLinus Torvalds return ret; 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds if (S_ISDIR(old_dentry->d_inode->i_mode)) 7991da177e4SLinus Torvalds old_dir_i->i_nlink--; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds return 0; 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds 804