name->len, name->name);
}
+int
+lafs_dir_roll_mini(struct inode *dir, int handle, int dirop,
+ u32 inum, char *name, int len)
+{
+ int err = 0;
+ struct dirop_handle doh, old_doh;
+ struct datablock *inodb = NULL, *olddb = NULL;
+ struct inode *inode = NULL;
+ struct rename_roll *rr = NULL, **rrp;
+ struct fs *fs = fs_from_inode(dir);
+ int last;
+
+ if (inum)
+ inode = lafs_iget(dir->i_sb, inum, SYNC);
+ if (IS_ERR(inode))
+ return PTR_ERR(inode);
+ if (!inode && dirop != DIROP_REN_TARGET)
+ return -EINVAL;
+
+ switch (dirop) {
+ default:
+ err = -EINVAL;
+ break;
+ case DIROP_LINK:
+ /* name doesn't exist - we create it. */
+ err = dir_create_prepare(fs, dir, name, len,
+ inum, mode_to_dt(inode->i_mode), &doh);
+ inodb = lafs_inode_dblock(dir, SYNC, MKREF(roll_dir));
+ if (IS_ERR(inodb))
+ err = PTR_ERR(inodb);
+
+ err = err ?: dir_create_pin(&doh);
+ err = err ?: lafs_pin_dblock(inodb, ReleaseSpace);
+ if (err < 0) {
+ dir_create_abort(&doh);
+ break;
+ }
+ inode_inc_link_count(inode);
+ lafs_inode_checkpin(inode);
+ lafs_dirty_dblock(inodb);
+ clear_bit(B_PinPending, &inodb->b.flags);
+ dir_create_commit(&doh, fs, dir, name, len,
+ inum, mode_to_dt(inode->i_mode));
+ err = 0;
+ break;
+
+ case DIROP_UNLINK:
+ /* Name exists, we need to remove it */
+ last = (inode->i_nlink == 1);
+ err = dir_delete_prepare(fs, dir, name, len, &doh);
+ inodb = lafs_inode_dblock(inode, SYNC, MKREF(roll_dir));
+ if (IS_ERR(inode))
+ err = PTR_ERR(inodb);
+ if (last && !err)
+ err = lafs_make_orphan(fs, inodb);
+ if (err) {
+ dir_delete_abort(&doh);
+ break;
+ }
+ lafs_iolock_block(&inodb->b);
+ set_bit(B_PinPending, &inodb->b.flags);
+ lafs_iounlock_block(&inodb->b);
+ err = dir_delete_pin(&doh);
+ err = err ?: lafs_pin_dblock(inodb, ReleaseSpace);
+ if (err < 0) {
+ dir_delete_abort(&doh);
+ break;
+ }
+ inode_dec_link_count(inode);
+ dir_delete_commit(&doh, fs, dir, name, len);
+ lafs_inode_checkpin(inode);
+ lafs_dirty_dblock(inodb);
+ clear_bit(B_PinPending, &inodb->b.flags);
+ err = 0;
+ break;
+
+ case DIROP_REN_SOURCE:
+ rr = kmalloc(sizeof(*rr) + len, GFP_KERNEL);
+ if (!rr) {
+ err = -ENOMEM;
+ break;
+ }
+ rr->next = fs->pending_renames;
+ rr->key = handle;
+ rr->dir = dir; igrab(dir);
+ rr->inode = inode; igrab(inode);
+ rr->nlen = len;
+ strncpy(rr->name, name, len);
+ rr->name[len] = 0;
+ fs->pending_renames = rr;
+ rr = NULL;
+ break;
+
+ case DIROP_REN_TARGET:
+ rrp = &fs->pending_renames;
+ while (*rrp) {
+ rr = *rrp;
+ if (rr->key == handle)
+ break;
+ rrp = &rr->next;
+ }
+ if (!*rrp) {
+ rr = NULL;
+ err = -EINVAL;
+ break;
+ }
+ *rrp = rr->next;
+ rr->next = NULL;
+
+ last = (inode && inode->i_nlink == 1);
+
+ /* FIXME check both are dirs or non-dirs, and that a
+ * target directory is empty */
+ err = dir_delete_prepare(fs, rr->dir,
+ rr->name, rr->nlen,
+ &old_doh);
+ olddb = lafs_inode_dblock(rr->inode, SYNC, MKREF(roll_dir));
+ if (IS_ERR(olddb))
+ err = PTR_ERR(olddb);
+ if (inode) {
+ /*unlink inode, update name */
+ err = dir_update_prepare(fs, dir, name, len, &doh)
+ ?: err;
+ inodb = lafs_inode_dblock(inode, SYNC, MKREF(roll_dir));
+ if (IS_ERR(inodb))
+ err = PTR_ERR(inodb);
+ if (last && !err)
+ err = lafs_make_orphan(fs, inodb);
+ lafs_iolock_block(&inodb->b);
+ set_bit(B_PinPending, &inodb->b.flags);
+ lafs_iounlock_block(&inodb->b);
+ } else
+ /* create new link */
+ err = dir_create_prepare(fs, dir, name, len,
+ rr->inode->i_ino,
+ mode_to_dt(rr->inode->i_mode),
+ &doh) ?: err;
+
+ if (!err) {
+ lafs_iolock_block(&olddb->b);
+ set_bit(B_PinPending, &olddb->b.flags);
+ lafs_iounlock_block(&olddb->b);
+ }
+
+ err = err ?: dir_delete_pin(&old_doh);
+ err = err ?: lafs_pin_dblock(olddb, ReleaseSpace);
+ if (inode) {
+ err = err ?: lafs_pin_dblock(inodb, ReleaseSpace);
+ err = err ?: dir_update_pin(&doh);
+ } else
+ err = err ?: dir_create_pin(&doh);
+ if (err < 0) {
+ dir_delete_abort(&old_doh);
+ if (inode)
+ dir_update_abort(&doh);
+ else
+ dir_create_abort(&doh);
+ break;
+ }
+ dir_delete_commit(&old_doh, fs, rr->dir, rr->name, rr->nlen);
+ if (S_ISDIR(rr->inode->i_mode)) {
+ inode_dec_link_count(rr->dir);
+ if (!inode)
+ inode_inc_link_count(dir);
+ }
+ if (inode)
+ dir_update_commit(fs, rr->inode->i_ino,
+ mode_to_dt(rr->inode->i_mode),
+ &doh);
+ else
+ dir_create_commit(&doh, fs, dir, name, len,
+ rr->inode->i_ino,
+ mode_to_dt(rr->inode->i_mode));
+ LAFSI(rr->inode)->md.file.parent = dir->i_ino;
+ if (inode) {
+ if (S_ISDIR(inode->i_mode))
+ inode_dec_link_count(inode);
+ inode_dec_link_count(inode);
+ lafs_inode_checkpin(inode);
+ }
+ lafs_dirty_inode(rr->inode);
+ lafs_inode_checkpin(rr->dir);
+ lafs_inode_checkpin(dir);
+ clear_bit(B_PinPending, &olddb->b.flags);
+ if (inode) {
+ clear_bit(B_PinPending, &inodb->b.flags);
+ putdref(inodb, MKREF(dir_roll));
+ }
+ err = 0;
+ break;
+ }
+ if (inode && !IS_ERR(inode))
+ iput(inode);
+ if (inodb && !IS_ERR(inodb))
+ putdref(inodb, MKREF(roll_dir));
+ if (olddb && !IS_ERR(olddb))
+ putdref(olddb, MKREF(roll_dir));
+ if (rr) {
+ iput(rr->dir);
+ iput(rr->inode);
+ kfree(rr);
+ }
+ return err;
+}
/*------------------------------------------------------------
* Now we have the lowlevel operations in place, we
* can implement the VFS interface.
lafs_inode_checkpin(inode);
lafs_dirty_dblock(inodb);
clear_bit(B_PinPending, &inodb->b.flags);
- putdref(inodb, MKREF(inode_update));
+ putdref(inodb, MKREF(link));
dir_log_commit(&uh, fs, dir, &to->d_name, inode->i_ino,
DIROP_LINK, NULL);
clear_bit(B_PinPending, &inodb->b.flags);
abort:
if (!IS_ERR(inodb))
- putdref(inodb, MKREF(inode_update));
+ putdref(inodb, MKREF(link));
dir_create_abort(&doh);
lafs_cluster_update_abort(&uh);
return err;