static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; uint32_t now; /* Don't let people make hard links to bad inodes. */ if (!f->inocache) return -EIO; if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; /* XXX: This is ugly */ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; now = get_seconds(); ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); if (!ret) { mutex_lock(&f->sem); old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink; mutex_unlock(&f->sem); d_instantiate(dentry, old_dentry->d_inode); dir_i->i_mtime = dir_i->i_ctime = ITIME(now); ihold(old_dentry->d_inode); } return ret; }
static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; /* Don't let people make hard links to bad inodes. */ if (!f->inocache) return -EIO; if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; /* XXX: This is ugly */ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); if (!ret) { down(&f->sem); old_dentry->d_inode->i_nlink = ++f->inocache->nlink; up(&f->sem); d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); } return ret; }
int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name) { struct jffs2_sb_info *c; struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; c = &old_d_inode->i_sb->jffs2_sb; /* XXX: This is ugly */ type = (old_d_inode->i_mode & S_IFMT) >> 12; if (!type) { type = DT_REG; } ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, (const char * )d_name, strlen((char *)d_name)); if (!ret) { down(&f->sem); old_d_inode->i_nlink = ++f->inocache->nlink; up(&f->sem); } return ret; }
static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { int ret; /* Can't link a bad inode. */ if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache) return -EIO; if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; ret = jffs2_do_link(old_dentry, dir_i, dentry, 0); if (!ret) { d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); } return ret; }
int jffs2_rename (struct inode *old_dir_i, struct inode *d_inode, struct qstr *old_d_name, struct inode *new_dir_i, struct qstr *new_d_name) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); uint8_t type; /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ /* XXX: This is ugly */ type = (d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), d_inode->i_ino, type, new_d_name->name, new_d_name->len); if (ret) return ret; /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), old_d_name->name, old_d_name->len, NULL); /* We don't touch inode->i_nlink */ if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); down(&f->sem); d_inode->i_nlink = f->inocache->nlink++; up(&f->sem); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); } return ret; }
int jffs2_link (struct inode *old_d_inode, struct inode *dir_i, struct qstr *d_name) { struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; /* XXX: This is ugly */ uint8_t type = (old_d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, d_name->name, d_name->len); if (!ret) { down(&f->sem); old_d_inode->i_nlink = ++f->inocache->nlink; up(&f->sem); } return ret; }
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; uint8_t type; uint32_t now; /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ if (new_dentry->d_inode) { victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); if (S_ISDIR(new_dentry->d_inode->i_mode)) { struct jffs2_full_dirent *fd; mutex_lock(&victim_f->sem); for (fd = victim_f->dents; fd; fd = fd->next) { if (fd->ino) { mutex_unlock(&victim_f->sem); return -ENOTEMPTY; } } mutex_unlock(&victim_f->sem); } } /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ /* XXX: This is ugly */ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; now = get_seconds(); ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), old_dentry->d_inode->i_ino, type, new_dentry->d_name.name, new_dentry->d_name.len, now); if (ret) return ret; if (victim_f) { /* There was a victim. Kill it off nicely */ if (S_ISDIR(new_dentry->d_inode->i_mode)) clear_nlink(new_dentry->d_inode); else drop_nlink(new_dentry->d_inode); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { mutex_lock(&victim_f->sem); if (S_ISDIR(new_dentry->d_inode->i_mode)) victim_f->inocache->pino_nlink = 0; else victim_f->inocache->pino_nlink--; mutex_unlock(&victim_f->sem); } } /* If it was a directory we moved, and there was no victim, increase i_nlink on its new parent */ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) inc_nlink(new_dir_i); /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); /* We don't touch inode->i_nlink */ if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); mutex_lock(&f->sem); inc_nlink(old_dentry->d_inode); if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode)) f->inocache->pino_nlink++; mutex_unlock(&f->sem); ; /* Might as well let the VFS know */ d_instantiate(new_dentry, old_dentry->d_inode); ihold(old_dentry->d_inode); new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); return ret; } if (S_ISDIR(old_dentry->d_inode->i_mode)) drop_nlink(old_dir_i); new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); return 0; }
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; uint8_t type; /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ if (new_dentry->d_inode) { victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); if (S_ISDIR(new_dentry->d_inode->i_mode)) { struct jffs2_full_dirent *fd; down(&victim_f->sem); for (fd = victim_f->dents; fd; fd = fd->next) { if (fd->ino) { up(&victim_f->sem); return -ENOTEMPTY; } } up(&victim_f->sem); } } /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ /* XXX: This is ugly */ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), old_dentry->d_inode->i_ino, type, new_dentry->d_name.name, new_dentry->d_name.len); if (ret) return ret; if (victim_f) { /* There was a victim. Kill it off nicely */ new_dentry->d_inode->i_nlink--; /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { down(&victim_f->sem); victim_f->inocache->nlink--; up(&victim_f->sem); } } /* If it was a directory we moved, and there was no victim, increase i_nlink on its new parent */ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) new_dir_i->i_nlink++; /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), old_dentry->d_name.name, old_dentry->d_name.len, NULL); /* We don't touch inode->i_nlink */ if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); down(&f->sem); old_dentry->d_inode->i_nlink++; if (f->inocache) f->inocache->nlink++; up(&f->sem); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); /* Might as well let the VFS know */ d_instantiate(new_dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); return ret; } if (S_ISDIR(old_dentry->d_inode->i_mode)) old_dir_i->i_nlink--; return 0; }
int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, struct _inode *new_dir_i, const unsigned char *new_d_name) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; uint8_t type; #if 0 /* FIXME -- this really doesn't belong in individual file systems. The fileio code ought to do this for us, or at least part of it */ if (new_dentry->d_inode) { if (S_ISDIR(d_inode->i_mode) && !S_ISDIR(new_dentry->d_inode->i_mode)) { /* Cannot rename directory over non-directory */ return -EINVAL; } victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); if (S_ISDIR(new_dentry->d_inode->i_mode)) { struct jffs2_full_dirent *fd; if (!S_ISDIR(d_inode->i_mode)) { /* Cannot rename non-directory over directory */ return -EINVAL; } down(&victim_f->sem); for (fd = victim_f->dents; fd; fd = fd->next) { if (fd->ino) { up(&victim_f->sem); return -ENOTEMPTY; } } up(&victim_f->sem); } } #endif /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ /* XXX: This is ugly */ type = (d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), d_inode->i_ino, type, (const char *)new_d_name, strlen((char *)new_d_name)); if (ret) return ret; if (victim_f) { /* There was a victim. Kill it off nicely */ /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { down(&victim_f->sem); victim_f->inocache->nlink--; up(&victim_f->sem); } } /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), (const char *)old_d_name, strlen((char *)old_d_name), NULL); if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); down(&f->sem); if (f->inocache) d_inode->i_nlink = f->inocache->nlink++; up(&f->sem); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); } return ret; }
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; uint8_t type; uint32_t now; /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ if (d_really_is_positive(new_dentry)) { victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); if (d_is_dir(new_dentry)) { struct jffs2_full_dirent *fd; mutex_lock(&victim_f->sem); for (fd = victim_f->dents; fd; fd = fd->next) { if (fd->ino) { mutex_unlock(&victim_f->sem); return -ENOTEMPTY; } } mutex_unlock(&victim_f->sem); } } /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ /* XXX: This is ugly */ type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; now = get_seconds(); ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), d_inode(old_dentry)->i_ino, type, new_dentry->d_name.name, new_dentry->d_name.len, now); if (ret) return ret; if (victim_f) { /* There was a victim. Kill it off nicely */ if (d_is_dir(new_dentry)) clear_nlink(d_inode(new_dentry)); else drop_nlink(d_inode(new_dentry)); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { mutex_lock(&victim_f->sem); if (d_is_dir(new_dentry)) victim_f->inocache->pino_nlink = 0; else victim_f->inocache->pino_nlink--; mutex_unlock(&victim_f->sem); } } /* If it was a directory we moved, and there was no victim, increase i_nlink on its new parent */ if (d_is_dir(old_dentry) && !victim_f) inc_nlink(new_dir_i); /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); /* We don't touch inode->i_nlink */ if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); mutex_lock(&f->sem); inc_nlink(d_inode(old_dentry)); if (f->inocache && !d_is_dir(old_dentry)) f->inocache->pino_nlink++; mutex_unlock(&f->sem); pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", __func__, ret); /* * We can't keep the target in dcache after that. * For one thing, we can't afford dentry aliases for directories. * For another, if there was a victim, we _can't_ set new inode * for that sucker and we have to trigger mount eviction - the * caller won't do it on its own since we are returning an error. */ d_invalidate(new_dentry); new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); return ret; } if (d_is_dir(old_dentry)) drop_nlink(old_dir_i); new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); return 0; }
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_inode_info *victim_f = NULL; /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ if (new_dentry->d_inode) { victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); if (S_ISDIR(new_dentry->d_inode->i_mode)) { struct jffs2_full_dirent *fd; down(&victim_f->sem); for (fd = victim_f->dents; fd; fd = fd->next) { if (fd->ino) { up(&victim_f->sem); return -ENOTEMPTY; } } up(&victim_f->sem); } } /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ if ( new_dentry->d_inode ) { jffs2_unlink(new_dir_i, new_dentry); } /* Make a hard link */ ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1); if (ret) return ret; if (victim_f) { /* There was a victim. Kill it off nicely */ new_dentry->d_inode->i_nlink--; /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { down(&victim_f->sem); victim_f->inocache->nlink--; up(&victim_f->sem); } } /* Unlink the original */ ret = jffs2_do_unlink(old_dir_i, old_dentry, 1); if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); down(&f->sem); if (f->inocache) old_dentry->d_inode->i_nlink = f->inocache->nlink++; up(&f->sem); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); /* Might as well let the VFS know */ d_instantiate(new_dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); } return ret; }