Exemple #1
0
int minix_create(struct inode * dir, struct dentry *dentry, int mode)
{
	int error;
	struct inode * inode;
	struct buffer_head * bh;
	struct minix_dir_entry * de;

	if (!dir)
		return -ENOENT;
	inode = minix_new_inode(dir);
	if (!inode)
		return -ENOSPC;
	inode->i_op = &minix_file_inode_operations;
	inode->i_mode = mode;
	mark_inode_dirty(inode);
	error = minix_add_entry(dir, dentry->d_name.name,
				dentry->d_name.len, &bh ,&de);
	if (error) {
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		return error;
	}
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	brelse(bh);
	d_instantiate(dentry, inode);
	return 0;
}
Exemple #2
0
int minix_mknod(register struct inode *dir, char *name, size_t len,
		int mode, int rdev)
{
    int error;
    register struct inode *inode;
    struct buffer_head *bh;
    struct minix_dir_entry *de;

/*    if (!dir)
	return -ENOENT;*/	/* Already checked by do_mknod() */

    error = -EEXIST;
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	unmap_brelse(bh);
	goto mknod2;
    }
    error = -ENOSPC;
    inode = minix_new_inode(dir, (__u16)mode);
    if (!inode)
	goto mknod2;
/*----------------------------------------------------------------------*/
    if (S_ISBLK(mode) || S_ISCHR(mode))
	inode->i_rdev = to_kdev_t(rdev);
/*----------------------------------------------------------------------*/
    error = minix_add_entry(dir, name, len, inode->i_ino);
    if (error) {
	inode->i_nlink--;
	inode->i_dirt = 1;
    }
    iput(inode);
 mknod2:
    iput(dir);
    return error;
}
Exemple #3
0
int minix_create(register struct inode *dir, char *name, size_t len,
		 int mode, struct inode **result)
{
    register struct inode *inode = NULL;
    int error;

    error = -ENOENT;
    if (!dir)
	goto create2;

    error = -ENOSPC;
    inode = minix_new_inode(dir, (__u16)mode);
    if (!inode)
	goto create1;
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
    error = minix_add_entry(dir, name, len, inode->i_ino);
    if(error) {
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	inode = NULL;
    }
 create1:
    iput(dir);
 create2:
    *result = inode;
    return error;
}
Exemple #4
0
int minix_mkdir(register struct inode *dir, char *name, size_t len, int mode)
{
    int error;
    register struct inode *inode;
    struct buffer_head *bh;
    struct minix_dir_entry *de;

    error = -EINVAL;
    if (!dir || !dir->i_sb)
	goto mkdir2;
    error = -EMLINK;
    if (dir->i_nlink >= MINIX_LINK_MAX)
	goto mkdir2;

    error = -EEXIST;
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	unmap_brelse(bh);
	goto mkdir2;
    }
    error = -ENOSPC;
    inode = minix_new_inode(dir, (__u16)mode);
    if (!inode)
	goto mkdir2;
/*--------------------------------------------------------------------------------*/
    debug("m_mkdir: new_inode succeeded\n");
    debug("m_mkdir: starting minix_bread\n");
    bh = minix_bread(inode, 0, 1);
    if (!bh) {
	goto mkdir1;
    }
    debug("m_mkdir: read succeeded\n");
    inode->i_size = (dir->i_sb->u.minix_sb.s_dirsize << 1);
    map_buffer(bh);
    de = (struct minix_dir_entry *) bh->b_data;
    de->inode = inode->i_ino;
    strcpy(de->name, ".");
    de = (struct minix_dir_entry *)(((char *)de) + dir->i_sb->u.minix_sb.s_dirsize);
    de->inode = dir->i_ino;
    strcpy(de->name, "..");
    mark_buffer_dirty(bh, 1);
    unmap_brelse(bh);
    debug("m_mkdir: dir_block update succeeded\n");
/*--------------------------------------------------------------------------------*/
    error = minix_add_entry(dir, name, len, inode->i_ino);
    if (error) {
      mkdir1:
	inode->i_nlink--;
    }
    else {
	inode->i_nlink++;
	dir->i_nlink++;
    }
    inode->i_dirt = 1;
    iput(inode);
 mkdir2:
    iput(dir);
    debug("m_mkdir: done!\n");
    return error;
}
Exemple #5
0
int minix_create(register struct inode *dir, char *name, size_t len,
		 int mode, struct inode **result)
{
    register struct inode *inode;
    struct buffer_head *bh;
    struct minix_dir_entry *de;
    int error;

    *result = NULL;
    if (!dir)
	return -ENOENT;
    inode = minix_new_inode(dir);
    if (!inode) {
	iput(dir);
	return -ENOSPC;
    }
    inode->i_op = &minix_file_inode_operations;
    inode->i_mode = (__u16) mode;
    inode->i_dirt = 1;
    error = minix_add_entry(dir, name, len, &bh, &de);
    if (error) {
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	iput(dir);
	return error;
    }
    de->inode = inode->i_ino;
    mark_buffer_dirty(bh, 1);
    brelse(bh);
    iput(dir);
    *result = inode;
    return 0;
}
Exemple #6
0
int minix_link(register struct inode *oldinode, register struct inode *dir,
		char *name, size_t len)
{
    int error;
    struct buffer_head *bh;
    struct minix_dir_entry *de;

    error = -EPERM;
    if (S_ISDIR(oldinode->i_mode))
	goto mlink_err;
    error = -EMLINK;
    if (oldinode->i_nlink >= MINIX_LINK_MAX)
	goto mlink_err;
    error = -EEXIST;
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	unmap_brelse(bh);
	goto mlink_err;
    }
    error = minix_add_entry(dir, name, len, oldinode->i_ino);
    if (!error) {
	oldinode->i_nlink++;
	oldinode->i_ctime = CURRENT_TIME;
	oldinode->i_dirt = 1;
    }
 mlink_err:
    iput(oldinode);
    iput(dir);
    return error;
}
Exemple #7
0
int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
	int error;
	struct inode * inode;
	struct buffer_head * bh, *dir_block;
	struct minix_dir_entry * de;
	struct minix_sb_info * info;

	if (!dir || !dir->i_sb)
		return -EINVAL;
	info = &dir->i_sb->u.minix_sb;
	bh = minix_find_entry(dir, dentry->d_name.name,
			      dentry->d_name.len, &de);
	if (bh) {
		brelse(bh);
		return -EEXIST;
	}
	if (dir->i_nlink >= info->s_link_max)
		return -EMLINK;
	inode = minix_new_inode(dir);
	if (!inode)
		return -ENOSPC;
	inode->i_op = &minix_dir_inode_operations;
	inode->i_size = 2 * info->s_dirsize;
	dir_block = minix_bread(inode,0,1);
	if (!dir_block) {
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		return -ENOSPC;
	}
	de = (struct minix_dir_entry *) dir_block->b_data;
	de->inode=inode->i_ino;
	strcpy(de->name,".");
	de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize);
	de->inode = dir->i_ino;
	strcpy(de->name,"..");
	inode->i_nlink = 2;
	mark_buffer_dirty(dir_block, 1);
	brelse(dir_block);
	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
	if (dir->i_mode & S_ISGID)
		inode->i_mode |= S_ISGID;
	mark_inode_dirty(inode);
	error = minix_add_entry(dir, dentry->d_name.name,
				dentry->d_name.len, &bh, &de);
	if (error) {
		inode->i_nlink=0;
		iput(inode);
		return error;
	}
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	dir->i_nlink++;
	mark_inode_dirty(dir);
	brelse(bh);
	d_instantiate(dentry, inode);
	return 0;
}
Exemple #8
0
int minix_symlink(struct inode *dir, char *name, size_t len, char *symname)
{
    struct minix_dir_entry *de;
    register struct inode *inode = NULL;
    struct buffer_head *bh = NULL;
    register struct buffer_head *name_block = NULL;
    int i;
    char c;

    if (!(inode = minix_new_inode(dir))) {
	iput(dir);
	return -ENOSPC;
    }
    inode->i_mode = (__u16) (S_IFLNK | 0777);
    inode->i_op = &minix_symlink_inode_operations;
    name_block = minix_bread(inode, 0, 1);
    if (!name_block) {
	iput(dir);
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	return -ENOSPC;
    }
    map_buffer(name_block);
    i = 0;
    while (i < 1023 && (c = *(symname++)))
	name_block->b_data[i++] = c;
    name_block->b_data[i] = 0;
    mark_buffer_dirty(name_block, 1);
    unmap_brelse(name_block);
    inode->i_size = (__u32) i;
    inode->i_dirt = 1;
    bh = minix_find_entry(dir, name, len, &de);
    map_buffer(bh);
    if (bh) {
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	unmap_brelse(bh);
	iput(dir);
	return -EEXIST;
    }
    i = minix_add_entry(dir, name, len, &bh, &de);
    if (i) {
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	iput(dir);
	return i;
    }
    de->inode = inode->i_ino;
    mark_buffer_dirty(bh, 1);
    brelse(bh);
    iput(dir);
    iput(inode);
    return 0;
}
Exemple #9
0
int minix_symlink(struct inode * dir, struct dentry *dentry,
		  const char * symname)
{
	struct minix_dir_entry * de;
	struct inode * inode = NULL;
	struct buffer_head * bh = NULL, * name_block = NULL;
	int i;
	char c;

	if (!(inode = minix_new_inode(dir)))
		return -ENOSPC;

	inode->i_mode = S_IFLNK | 0777;
	inode->i_op = &minix_symlink_inode_operations;
	name_block = minix_bread(inode,0,1);
	if (!name_block) {
		inode->i_nlink--;
	        mark_inode_dirty(inode);
		iput(inode);
		return -ENOSPC;
	}
	i = 0;
	while (i < 1023 && (c=*(symname++)))
		name_block->b_data[i++] = c;
	name_block->b_data[i] = 0;
	mark_buffer_dirty(name_block, 1);
	brelse(name_block);
	inode->i_size = i;
	mark_inode_dirty(inode);
	bh = minix_find_entry(dir, dentry->d_name.name,
			      dentry->d_name.len, &de);
	if (bh) {
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		brelse(bh);
		return -EEXIST;
	}
	i = minix_add_entry(dir, dentry->d_name.name,
			    dentry->d_name.len, &bh, &de);
	if (i) {
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		return i;
	}
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	brelse(bh);
	d_instantiate(dentry, inode);
	return 0;
}
Exemple #10
0
int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
	int error;
	struct inode * inode;
	struct buffer_head * bh;
	struct minix_dir_entry * de;

	if (!dir)
		return -ENOENT;
	bh = minix_find_entry(dir, dentry->d_name.name,
			      dentry->d_name.len, &de);
	if (bh) {
		brelse(bh);
		return -EEXIST;
	}
	inode = minix_new_inode(dir);
	if (!inode)
		return -ENOSPC;
	inode->i_uid = current->fsuid;
	inode->i_mode = mode;
	inode->i_op = NULL;
	if (S_ISREG(inode->i_mode))
		inode->i_op = &minix_file_inode_operations;
	else if (S_ISCHR(inode->i_mode))
		inode->i_op = &chrdev_inode_operations;
	else if (S_ISBLK(inode->i_mode))
		inode->i_op = &blkdev_inode_operations;
	else if (S_ISFIFO(inode->i_mode))
		init_fifo(inode);
	if (S_ISBLK(mode) || S_ISCHR(mode))
		inode->i_rdev = to_kdev_t(rdev);
	mark_inode_dirty(inode);
	error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
	if (error) {
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		return error;
	}
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	brelse(bh);
	d_instantiate(dentry, inode);
	return 0;
}
Exemple #11
0
int minix_symlink(struct inode *dir, char *name, size_t len, char *symname)
{
    int error;
    register struct inode *inode;
    register struct buffer_head *bh;
    struct minix_dir_entry *de;

    error = -EEXIST;
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	unmap_brelse(bh);
	goto symlink2;
    }
    error = -ENOSPC;
    inode = minix_new_inode(dir, S_IFLNK);
    if (!inode)
	goto symlink2;
/*----------------------------------------------------------------------*/
    bh = minix_bread(inode, 0, 1);
    if (!bh)
	goto symlink1;
    map_buffer(bh);
    if((error = strlen_fromfs(symname)) > 1023)
	error = 1023;
    memcpy_fromfs(bh->b_data, symname, error);
    bh->b_data[error] = 0;
    inode->i_size = (__u32) error;
    mark_buffer_dirty(bh, 1);
    unmap_brelse(bh);
/*----------------------------------------------------------------------*/
    error = minix_add_entry(dir, name, len, inode->i_ino);
    if (error) {
      symlink1:
	inode->i_nlink--;
	inode->i_dirt = 1;
    }
    iput(inode);
 symlink2:
    iput(dir);
    return error;
}
Exemple #12
0
int minix_link(register struct inode *oldinode, register struct inode *dir,
		char *name, size_t len)
{
    int error;
    struct minix_dir_entry *de;
    struct buffer_head *bh;

    if (S_ISDIR(oldinode->i_mode)) {
	iput(oldinode);
	iput(dir);
	return -EPERM;
    }
    if (oldinode->i_nlink >= MINIX_LINK_MAX) {
	iput(oldinode);
	iput(dir);
	return -EMLINK;
    }
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	brelse(bh);
	iput(dir);
	iput(oldinode);
	return -EEXIST;
    }
    error = minix_add_entry(dir, name, len, &bh, &de);
    if (error) {
	iput(dir);
	iput(oldinode);
	return error;
    }
    de->inode = oldinode->i_ino;
    mark_buffer_dirty(bh, 1);
    brelse(bh);
    iput(dir);
    oldinode->i_nlink++;
    oldinode->i_ctime = CURRENT_TIME;
    oldinode->i_dirt = 1;
    iput(oldinode);
    return 0;
}
Exemple #13
0
int minix_create(register struct inode *dir, char *name, size_t len,
		 int mode, struct inode **result)
{
    register struct inode *inode = NULL;
    int error;

    if (!dir)
	error = -ENOENT;
    else if (!(inode = minix_new_inode(dir, (__u16)mode)))
	error = -ENOSPC;
    else {
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
	if ((error = minix_add_entry(dir, name, len, inode->i_ino))) {
	    inode->i_nlink--;
	    inode->i_dirt = 1;
	    iput(inode);
	    inode = NULL;
	}
	iput(dir);
    }
    *result = inode;
    return error;
}
Exemple #14
0
int minix_link(struct dentry * old_dentry, struct inode * dir,
	       struct dentry *dentry)
{
	int error;
	struct inode *inode = old_dentry->d_inode;
	struct minix_dir_entry * de;
	struct buffer_head * bh;

	if (S_ISDIR(inode->i_mode))
		return -EPERM;

	if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
		return -EMLINK;

	bh = minix_find_entry(dir, dentry->d_name.name,
			      dentry->d_name.len, &de);
	if (bh) {
		brelse(bh);
		return -EEXIST;
	}
	error = minix_add_entry(dir, dentry->d_name.name,
				dentry->d_name.len, &bh, &de);
	if (error) {
		brelse(bh);
		return error;
	}
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	brelse(bh);
	inode->i_nlink++;
	inode->i_ctime = CURRENT_TIME;
	mark_inode_dirty(inode);
	inode->i_count++;
	d_instantiate(dentry, inode);
	return 0;
}
Exemple #15
0
int minix_mknod(register struct inode *dir, char *name, size_t len,
		int mode, int rdev)
{
    int error;
    register struct inode *inode;
    struct buffer_head *bh;
    struct minix_dir_entry *de;

    if (!dir)
	return -ENOENT;
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	brelse(bh);
	iput(dir);
	return -EEXIST;
    }
    inode = minix_new_inode(dir);
    if (!inode) {
	iput(dir);
	return -ENOSPC;
    }
    inode->i_uid = current->euid;
    inode->i_mode = (__u16) mode;
    inode->i_op = NULL;

    minix_set_ops(inode);

    if (S_ISDIR(inode->i_mode))
	if (dir->i_mode & S_ISGID)
	    inode->i_mode |= S_ISGID;

    if (S_ISBLK(mode) || S_ISCHR(mode))
	inode->i_rdev = to_kdev_t(rdev);
    inode->i_dirt = 1;
    error = minix_add_entry(dir, name, len, &bh, &de);
#if 1
    if (error) {
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	iput(dir);
	return error;
    }
    de->inode = inode->i_ino;
    mark_buffer_dirty(bh, 1);
    brelse(bh);
    iput(dir);
    iput(inode);
    return 0;
#else  /* MJN3: If the ordering of the iput()s isn't important, do this. */
    if (error) {
	inode->i_nlink--;
	inode->i_dirt = 1;
    } else {
	de->inode = inode->i_ino;
	mark_buffer_dirty(bh, 1);
	brelse(bh);
    }
    iput(dir);
    iput(inode);
    return error;
#endif
}
Exemple #16
0
int minix_mkdir(register struct inode *dir, char *name, size_t len, int mode)
{
    int error;
    register struct inode *inode;
    struct buffer_head *dir_block;
    struct buffer_head *bh;
    struct minix_dir_entry *de;

    if (!dir || !dir->i_sb) {
	iput(dir);
	return -EINVAL;
    }
    bh = minix_find_entry(dir, name, len, &de);
    if (bh) {
	brelse(bh);
	iput(dir);
	return -EEXIST;
    }
    if (dir->i_nlink >= MINIX_LINK_MAX) {
	iput(dir);
	return -EMLINK;
    }
    inode = minix_new_inode(dir);
    if (!inode) {
	iput(dir);
	return -ENOSPC;
    }
    debug("m_mkdir: new_inode succeeded\n");
    inode->i_op = &minix_dir_inode_operations;
    inode->i_size = 2 * dir->i_sb->u.minix_sb.s_dirsize;
    debug("m_mkdir: starting minix_bread\n");
    dir_block = minix_bread(inode, 0, 1);
    if (!dir_block) {
	iput(dir);
	inode->i_nlink--;
	inode->i_dirt = 1;
	iput(inode);
	return -ENOSPC;
    }
    debug("m_mkdir: read succeeded\n");
    map_buffer(dir_block);
    de = (struct minix_dir_entry *) dir_block->b_data;
    de->inode = inode->i_ino;
    strcpy(de->name, ".");
    de =
	(struct minix_dir_entry *) (dir_block->b_data +
				    dir->i_sb->u.minix_sb.s_dirsize);
    de->inode = dir->i_ino;
    strcpy(de->name, "..");
    inode->i_nlink = 2;
    mark_buffer_dirty(dir_block, 1);
    unmap_brelse(dir_block);
    debug("m_mkdir: dir_block update succeeded\n");
    inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs.umask);
    if (dir->i_mode & S_ISGID)
	inode->i_mode |= S_ISGID;
    inode->i_dirt = 1;
    error = minix_add_entry(dir, name, len, &bh, &de);
    if (error) {
	iput(dir);
	inode->i_nlink = 0;
	iput(inode);
	return error;
    }
    map_buffer(bh);
    de->inode = inode->i_ino;
    mark_buffer_dirty(bh, 1);
    dir->i_nlink++;
    dir->i_dirt = 1;
    iput(dir);
    iput(inode);
    unmap_brelse(bh);
    debug("m_mkdir: done!\n");
    return 0;
}
Exemple #17
0
/*
 * rename uses retrying to avoid race-conditions: at least they should be minimal.
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 * checks fail, it tries to restart itself again. Very practical - no changes
 * are done until we know everything works ok.. and then all the changes can be
 * done in one fell swoop when we have claimed all the buffers needed.
 *
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
			   struct inode * new_dir, struct dentry *new_dentry)
{
	struct inode * old_inode, * new_inode;
	struct buffer_head * old_bh, * new_bh, * dir_bh;
	struct minix_dir_entry * old_de, * new_de;
	struct minix_sb_info * info;
	int retval;

	info = &old_dir->i_sb->u.minix_sb;
	goto start_up;
try_again:
	brelse(old_bh);
	brelse(new_bh);
	brelse(dir_bh);
	current->counter = 0;
	schedule();
start_up:
	old_inode = new_inode = NULL;
	old_bh = new_bh = dir_bh = NULL;
	old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
				  old_dentry->d_name.len, &old_de);
	retval = -ENOENT;
	if (!old_bh)
		goto end_rename;
	old_inode = old_dentry->d_inode;
	retval = -EPERM;
	new_inode = new_dentry->d_inode;
	new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
				  new_dentry->d_name.len, &new_de);
	if (new_bh) {
		if (!new_inode) {
			brelse(new_bh);
			new_bh = NULL;
		}
	}
	if (new_inode == old_inode) {
		retval = 0;
		goto end_rename;
	}
	if (S_ISDIR(old_inode->i_mode)) {
		retval = -EINVAL;
		if (is_subdir(new_dentry, old_dentry))
			goto end_rename;
		if (new_inode) {
			/* Prune any children before testing for busy */
			if (new_dentry->d_count > 1)
				shrink_dcache_parent(new_dentry);
			retval = -EBUSY;
			if (new_dentry->d_count > 1)
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
			retval = -EBUSY;
		}
		retval = -EIO;
		dir_bh = minix_bread(old_inode,0,0);
		if (!dir_bh)
			goto end_rename;
		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
			goto end_rename;
		retval = -EMLINK;
		if (!new_inode && new_dir->i_nlink >= info->s_link_max)
			goto end_rename;
	}
	if (!new_bh) {
		retval = minix_add_entry(new_dir,
					 new_dentry->d_name.name,
					 new_dentry->d_name.len,
					 &new_bh, &new_de);
		if (retval)
			goto end_rename;
	}
/* sanity checking before doing the rename - avoid races */
	if (new_inode && (new_de->inode != new_inode->i_ino))
		goto try_again;
	if (new_de->inode && !new_inode)
		goto try_again;
	if (old_de->inode != old_inode->i_ino)
		goto try_again;
/* ok, that's it */
	old_de->inode = 0;
	new_de->inode = old_inode->i_ino;
	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(old_dir);
	old_dir->i_version = ++event;
	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(new_dir);
	new_dir->i_version = ++event;
	if (new_inode) {
		new_inode->i_nlink--;
		new_inode->i_ctime = CURRENT_TIME;
		mark_inode_dirty(new_inode);
	}
	mark_buffer_dirty(old_bh, 1);
	mark_buffer_dirty(new_bh, 1);
	if (dir_bh) {
		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
		mark_buffer_dirty(dir_bh, 1);
		old_dir->i_nlink--;
		mark_inode_dirty(old_dir);
		if (new_inode) {
			new_inode->i_nlink--;
			mark_inode_dirty(new_inode);
		} else {
			new_dir->i_nlink++;
			mark_inode_dirty(new_dir);
		}
	}
	/* Update the dcache */
	d_move(old_dentry, new_dentry);
	retval = 0;
end_rename:
	brelse(dir_bh);
	brelse(old_bh);
	brelse(new_bh);
	return retval;
}