]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
selftest: add a test for shadow:fixinodes
authorRalph Boehme <slow@samba.org>
Tue, 6 Jul 2021 05:24:00 +0000 (07:24 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 14 Jul 2021 08:09:31 +0000 (08:09 +0000)
This will fail with

  Failed to open file \@GMT-2015.10.31-19.40.30\subdir\hardlink. NT_STATUS_ACCESS_DENIED

The open is failing in openat_pathref_fsp():

  [2021/07/06 04:58:17.677104, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/files.c:541(openat_pathref_fsp)
    openat_pathref_fsp: file [subdir/hardlink {@GMT-2015.10.31-19.40.30}] - dev/ino mismatch. Old (dev=64770, ino=3826943444). New (dev=64770, ino=1746568660).
  [2021/07/06 04:58:17.677114, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/files.c:568(openat_pathref_fsp)
    openat_pathref_fsp: Opening pathref for [subdir/hardlink {@GMT-2015.10.31-19.40.30}] failed: NT_STATUS_ACCESS_DENIED

The reason is subtle:

shadow_copy2 calculates inode numbers of snapshot files based on the path of the
file. The result of that when doing a path based stat() from filename_convert()
was

  [2021/07/06 04:58:17.676159, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/filename.c:1945(filename_convert_internal)
    filename_convert_internal: XXX smb_fname [subdir/hardlink {@GMT-2015.10.31-19.40.30}] (dev=64770, ino=3826943444).

which is the "Old" inode shown above.

Later in the open code called from openat_pathref_fsp() -> fd_openat() ->
non_widelink_open() since 4.14 we call SMB_VFS_FSTAT() where fsp->fsp_name will
be set to the new relative *basename* of the file:

  [2021/07/06 04:58:17.676917, 10, pid=95070, effective(1000, 1000), real(1000, 0), class=vfs] ../../source3/modules/vfs_default.c:1302(vfswrap_fstat)
    vfswrap_fstat: XXX fsp [hardlink {@GMT-2015.10.31-19.40.30}] (dev=64770, ino=3826943444)

So for stat() the hash function in called with the full path relative to the share
root:

  subdir/hardlink

while for fstat() the hash function will used

  hardlink

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/samba3.blackbox.shadow_copy_torture [new file with mode: 0644]
source3/script/tests/test_shadow_copy_torture.sh

diff --git a/selftest/knownfail.d/samba3.blackbox.shadow_copy_torture b/selftest/knownfail.d/samba3.blackbox.shadow_copy_torture
new file mode 100644 (file)
index 0000000..aa68c3f
--- /dev/null
@@ -0,0 +1 @@
+^samba3.blackbox.shadow_copy_torture.fix inodes with hardlink\(fileserver\)
index 68cd97e636406e96347101cefdbb15025ef960d9..e5dc0192e95d4c8573d3a662f3ff00914cd45a36 100755 (executable)
@@ -36,6 +36,9 @@ build_files()
     destdir=$1
 
     echo "$content" > $destdir/foo
+
+    mkdir -p $WORKDIR/subdir/
+    touch $WORKDIR/subdir/hardlink
 }
 
 # build a snapshots directory
@@ -48,6 +51,9 @@ build_snapshots()
     mkdir -p $snapdir/$SNAPSHOT
 
     build_files $snapdir/$SNAPSHOT
+
+    mkdir -p $snapdir/$SNAPSHOT/subdir
+    ln "$WORKDIR"/subdir/hardlink "$snapdir"/$SNAPSHOT/subdir/hardlink
 }
 
 build_stream_on_snapshot()
@@ -126,6 +132,24 @@ test_shadow_copy_openroot()
         failed=`expr $failed + 1`
 }
 
+test_shadow_copy_fix_inodes()
+{
+    local msg
+
+    msg=$1
+
+    #delete snapshots from previous tests
+    find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+    build_snapshots
+
+    out=$($SMBCLIENT \
+          -U $USERNAME%$PASSWORD \
+          "//$SERVER/shadow_write" \
+          -c "open $SNAPSHOT/subdir/hardlink") || failed=`expr $failed + 1`
+    echo $out
+    echo $out | grep "hardlink: for read/write fnum 1" || return 1
+}
+
 build_files $WORKDIR
 
 # test open for writing and write behaviour of snapshoted files
@@ -135,4 +159,6 @@ test_shadow_copy_stream "reading stream of snapshotted file"
 
 test_shadow_copy_openroot "opening root of shadow copy share"
 
+testit "fix inodes with hardlink" test_shadow_copy_fix_inodes || failed=`expr $failed + 1`
+
 exit $failed