Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
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;
	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;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
}
Esempio n. 10
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;
    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;
}
Esempio n. 11
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;
}