Subject: [nfsv4] Question on rename

From: Frank S Filz <[email-masked]>
Date: Tue, 16 Apr 2013 09:15:00 -0700

All the NFS RFCs have the following text:

If oldname and newname both refer to the same file (they might be
hard links of each other), then RENAME should perform no action and
return success.

I wonder what the intent of this. It seems to imply that if a/foo and
b/foo2 are hardlinks to the same file, that a rename a/foo -> b/foo2 would
result in no action, resulting in the directory entry a/foo still existing.

When I try this operation on a local file system, the directory entry a/foo
disappears and the link count goes from 2 to 1 when I ls -l b/foo2.

Am I misinterpreting this text?

Thanks

Frank

---

From: "Myklebust, Trond" <[email-masked]>
Date: Tue, 16 Apr 2013 17:32:18 +0000

On Tue, 2013-04-16 at 09:15 -0700, Frank S Filz wrote:
> b/foo2 are hardlinks to the same file, that a rename a/foo -> b/foo2
> would result in no action, resulting in the directory entry a/foo
> still existing.

It's a POSIX requirement.

> When I try this operation on a local file system, the directory entry
> a/foo disappears and the link count goes from 2 to 1 when I ls -l
> b/foo2.
> 

Your local filesystem is broken.

Cheers
  Trond
-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
[email-masked]
www.netapp.com

---

From: Frank S Filz <[email-masked]>
Date: Tue, 16 Apr 2013 10:37:44 -0700

[email-masked] wrote on 04/16/2013 09:15:00 AM:
> I wonder what the intent of this. It seems to imply that if a/foo
> and b/foo2 are hardlinks to the same file, that a rename a/foo -> b/
> foo2 would result in no action, resulting in the directory entry a/
> foo still existing.
>
> When I try this operation on a local file system, the directory
> entry a/foo disappears and the link count goes from 2 to 1 when I ls-l
b/foo2.
> Am I misinterpreting this text?

Ah, never mind, I should have looked at man 2 rename, which has the same
text (and testing the rename system call on local file system indeed shows
the system call follows this text).

Looks like the mv command, on the basis of stat of the two files, does an
unlink system call instead of a rename (which one might argue is somewhat
racy, but in any case is outside the scope of NFS (server or client).

Thanks

Frank Filz

---

From: "Myklebust, Trond" <[email-masked]>
Date: Tue, 16 Apr 2013 17:50:31 +0000

> Your local filesystem is broken.

Let me correct that: if you are using GNU mv, then _it_ is broken. GNU
mv seems to do a totally unwarranted unlink in that situation...

NetApp

---

From: Frank S Filz <[email-masked]>
Date: Tue, 16 Apr 2013 11:04:41 -0700

"Myklebust, Trond" <[email-masked]> wrote on 04/16/2013
> mv seems to do a totally unwarranted unlink in that situation...

I would tend to agree.

Frank

---

From: Malahal Naineni <[email-masked]>
Date: Tue, 16 Apr 2013 13:21:47 -0500

>    racy, but in any case is outside the scope of NFS (server or client).

"mv" does what is best here. It can't use rename() when both names point
to the same file. Having said that, what is the race here?  Thread A
doing "mv" and thread B doing unlink(oldname) followed by
creat(oldname), right? creat() can't create a new file if the file
already exists!

Looks to me, we have a race to begin with because of unlink/creat not
being atomic to begin with.

Regards, Malahal.

---

From: "Myklebust, Trond" <[email-masked]>
Date: Tue, 16 Apr 2013 18:39:30 +0000

> creat(oldname), right? creat() can't create a new file if the file

It's relying on 2 stat() calls in order to figure out if the 2 files are
the same. What guarantees that they still are when you finally get round
to doing the "unlink"?

IOW:

Client 1           Client 2
=========          ========
create b           create a
ln b c
mv b c             mv a b

According to the POSIX specifications for the 'mv' utility I can expect
that in the above situation, the contents of file 'a' should _always_ be
preserved (although the name may change to 'c') and the contents of file
'b' _may_ be preserved.

With GNU mv, on the other hand, a situation exists where we may end up
unlinking 'a'.

> being atomic to begin with.

??????

NetApp

---

From: Frank S Filz <[email-masked]>
Date: Tue, 16 Apr 2013 11:47:53 -0700

> the same. What guarantees that they still are when you finally get round

That wasn't the specific race I had in mind, but serves well...

mv should only use the stat calls to determine if the two paths are on the
same file system. If so, then it should simply call rename(). If not, then
it has to copy the file over, and then unlink the original. That of course
can't be done atomically (here I appreciate that drag and drop in GUI tree
browsers just does a copy when dragging from one file system to another, it
leaves the unlink on the source file system to be done by the USER as a
separate operation).

Frank

---

From: "Welch, Brent" <[email-masked]>
Date: Wed, 17 Apr 2013 01:43:30 +0000

The BSD "mv" command leaves the files alone when confronted with

touch foo
ln foo hardlink
mv foo hardlink

at this point, both foo and hardlink still exist.

--
Brent

From: [email-masked] [mailto:[email-masked]] On Behalf Of Frank S Filz
Sent: Tuesday, April 16, 2013 11:48 AM
To: Myklebust, Trond
Cc: [email-masked]; [email-masked]
Subject: Re: [nfsv4] Question on rename

mv should only use the stat calls to determine if the two paths are on the same file system. If so, then it should simply call rename(). If not, then it has to copy the file over, and then unlink the original. That of course can't be done atomically (here I appreciate that drag and drop in GUI tree browsers just does a copy when dragging from one file system to another, it leaves the unlink on the source file system to be done by the USER as a separate operation).

Frank

---

From: Nico Williams <[email-masked]>
Date: Tue, 16 Apr 2013 23:59:13 -0500

On Apr 16, 2013 2:48 PM, "Frank S Filz" <[email-masked]> wrote:
> mv should only use the stat calls to determine if the two paths are on
the same file system. If so, then it should simply call rename(). If not,
then it has to copy the file over, and then unlink the original. That of
course can't be done atomically (here I appreciate that drag and drop in
GUI tree browsers just does a copy when dragging from one file system to
another, it leaves the unlink on the source file system to be done by the
USER as a separate operation).

Nah, mv(1) should just call rename(2): it's the filesystem's job (well, the
VFS', perhaps, depending on the OS; people have wanted ZFS to allow
cross-dataset renames) to determine if the old and new name/object are in
the same fs or whether they are even the same.

Nico
--