9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: Alexander Viro <viro@math.psu.edu>
To: 9fans@cse.psu.edu
Subject: Re: [9fans] Df command in Plan9?
Date: Thu, 26 Oct 2000 00:54:58 -0400	[thread overview]
Message-ID: <Pine.GSO.4.21.0010250702190.12098-100000@weyl.math.psu.edu> (raw)
In-Reply-To: <39F65AD7.8195874E@arl.army.mil>



On Wed, 25 Oct 2000, Douglas A. Gwyn wrote:

> Boyd Roberts wrote:
> > ... it's working out whether
> > you're ripping out the tree from under yourself is the
> > nasty problem.
>
> But that's a move, not a rename.

rename(2) in 4.2BSD and other Unices that picked/inherited it _is_ move.
Yes, it's overcomplicated, it sucks badly wrt required locking, it has
extremely nasty potential for races with rmdir() and itself, yodda, yodda.
I have no idea why Kirk went for that horror. He did. Once it works right
it's a convenient thing to have around, but getting it work right...
<shudder> Apologies for self-quoting, but...
/*
 * The worst of all namespace operations - renaming directory. "Perverted"
 * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
 * Problems:
 *      a) we can get into loop creation. Check is done in is_subdir().
 *      b) race potential - two innocent renames can create a loop  together.
 *         That's where 4.4 screws up. Current fix: serialization on
 *         sb->s_vfs_rename_sem. We might be more accurate, but that's another
 *         story.
 *      c) we have to lock _three_ objects - parents and victim (if it exists).
 *         And that - after we got ->i_sem on parents (until then we don't know
 *         whether the target exists at all, let alone whether it is a directory
 *         or not). Solution: ->i_zombie. Taken only after ->i_sem. Always taken
 *         on link creation/removal of any kind. And taken (without ->i_sem) on
 *         directory that will be removed (both in rmdir() and here).
 *      d) some filesystems don't support opened-but-unlinked directories,
 *         either because of layout or because they are not ready to deal with
 *         all cases correctly. The latter will be fixed (taking this sort of
 *         stuff into VFS), but the former is not going away. Solution: the same
 *         trick as in rmdir().
 *	[ the latter had been fixed, the former == NFS and SMBFS these days ]
 *      e) conversion from fhandle to dentry may come in the wrong moment - when
 *         we are removing the target. Solution: we will have to grab ->i_zombie
 *         in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
 *         ->i_sem on parents, which works but leads to some truely excessive
 *         locking].
 */
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
{
        int error;
        struct inode *target;

        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;

        error = may_delete(old_dir, old_dentry, 1);
        if (error)
                return error;

        if (new_dir->i_dev != old_dir->i_dev)
                return -EXDEV;

        if (!new_dentry->d_inode)
                error = may_create(new_dir, new_dentry);
        else
                error = may_delete(new_dir, new_dentry, 1);
        if (error)
                return error;

        if (!old_dir->i_op || !old_dir->i_op->rename)
                return -EPERM;

        /*
         * If we are going to change the parent - check write permissions,
         * we'll need to flip '..'.
         */
        if (new_dir != old_dir)
                error = permission(old_dentry->d_inode, MAY_WRITE);
        if (error)
                return error;

        DQUOT_INIT(old_dir);
        DQUOT_INIT(new_dir);
        down(&old_dir->i_sb->s_vfs_rename_sem);
        error = -EINVAL;
        if (is_subdir(new_dentry, old_dentry))
                goto out_unlock;
        target = new_dentry->d_inode;
        if (target) { /* Hastur! Hastur! Hastur! */
                triple_down(&old_dir->i_zombie,
                            &new_dir->i_zombie,
                            &target->i_zombie);
                d_unhash(new_dentry);
        } else
                double_down(&old_dir->i_zombie,
                            &new_dir->i_zombie);
        if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir))
                error = -ENOENT;
        else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
                error = -EBUSY;
        else
                error = old_dir->i_op->rename(old_dir, old_dentry,
					      new_dir, new_dentry);
        if (target) {
                if (!error)
                        target->i_flags |= S_DEAD;
                triple_up(&old_dir->i_zombie,
                          &new_dir->i_zombie,
                          &target->i_zombie);
                if (d_unhashed(new_dentry))
                        d_rehash(new_dentry);
                dput(new_dentry);
        } else
                double_up(&old_dir->i_zombie,
                          &new_dir->i_zombie);

        if (!error)
                d_move(old_dentry,new_dentry);
out_unlock:
        up(&old_dir->i_sb->s_vfs_rename_sem);
        return error;
}

... and that's just the directory-specific part of VFS side of the thing,
after we got i_sem on parents and got dentries of source and target.
->i_op->rename() does fs-dependent part of work.

Full-blown rename() is painful, just as full-blown truncate() and correct
handling of symlinks. Nice to have on the userland side of things, but
kernel side is something. truncate()/mmap()/write() alone makes for a
serious S&M shop.




  reply	other threads:[~2000-10-26  4:54 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-10-20 20:31 Russ Cox
2000-10-20 21:44 ` Alexander Viro
2000-10-20 21:51   ` Boyd Roberts
2000-10-21  0:37   ` Rick Hohensee
2000-10-21 10:13     ` Alexander Viro
2000-10-22  0:13       ` Rick Hohensee
2000-10-22  0:25         ` Boyd Roberts
2000-10-22 15:41           ` Rick Hohensee
2000-10-23  9:02           ` Douglas A. Gwyn
2000-10-23 10:30             ` Alexander Viro
2000-10-24 11:37             ` Boyd Roberts
2000-10-25  8:30               ` Douglas A. Gwyn
2000-10-26  4:54                 ` Alexander Viro [this message]
2000-10-26  5:44                   ` Boyd Roberts
2000-10-22 11:34         ` Alexander Viro
2000-10-22 15:59           ` Rick Hohensee
2000-10-22 16:43             ` Alexander Viro
2000-10-23  5:06             ` Boyd Roberts
  -- strict thread matches above, loose matches on Subject: below --
2000-10-22 17:06 forsyth
2000-10-23  2:23 ` Rick Hohensee
2000-10-22 11:04 forsyth
2000-10-22 12:49 ` Boyd Roberts
2000-10-22 13:16 ` Alexander Viro
2000-10-22 16:07   ` Rick Hohensee
2000-10-22 16:31     ` Alexander Viro
2000-10-23  2:07       ` Rick Hohensee
2000-10-22 16:05 ` Rick Hohensee
2000-10-20 21:51 presotto
2000-10-20 20:22 Mark C. Otto

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.GSO.4.21.0010250702190.12098-100000@weyl.math.psu.edu \
    --to=viro@math.psu.edu \
    --cc=9fans@cse.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).