mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
smb/client: mark missing nlink values as unknown
Several SMB1 fallback and open responses do not provide the hard link
count. The SMB2 create-only query fallback has the same limitation.
These paths currently leave a zero link count or synthesize a value of
one and then expose it as authoritative metadata.
Mark those results with unknown_nlink so existing inodes keep their
cached link count and new inodes receive the usual sane default.
This was tested against Samba with "server min protocol = NT1". Mount
the share using SMB1 with Unix extensions disabled:
mount -t cifs //<server>/<share> /mnt/cifs \
-o username=<user>,vers=1.0,nounix
Create three names for the same inode and cache its real link count:
TESTDIR=/mnt/cifs/nlink-repro-$$
mkdir "$TESTDIR"
touch "$TESTDIR/file1"
ln "$TESTDIR/file1" "$TESTDIR/file2"
ln "$TESTDIR/file1" "$TESTDIR/file3"
stat -c 'before open: %h' "$TESTDIR/file1"
Open the file and read the link count through the open descriptor:
exec 3<"$TESTDIR/file1"
stat -Lc 'after open: %h' /proc/$$/fd/3
exec 3<&-
Clean up the test files:
rm -f "$TESTDIR/file1" "$TESTDIR/file2" "$TESTDIR/file3"
rmdir "$TESTDIR"
Before this change, the two stat commands report 3 and 1 because the
SMB1 open response overwrites the known link count. With this change,
both commands report 3.
Signed-off-by: Ze Tan <tanze@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
This commit is contained in:
@@ -542,6 +542,7 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
|
||||
data->reparse_point = false;
|
||||
data->adjust_tz = false;
|
||||
data->unknown_nlink = false;
|
||||
|
||||
/*
|
||||
* First try CIFSSMBQPathInfo() function which returns more info
|
||||
@@ -608,6 +609,7 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
fi.EASize = di->EaSize;
|
||||
}
|
||||
fi.NumberOfLinks = cpu_to_le32(1);
|
||||
data->unknown_nlink = true;
|
||||
fi.DeletePending = 0;
|
||||
fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY);
|
||||
cifs_buf_release(search_info.ntwrk_buf_start);
|
||||
@@ -630,6 +632,8 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb));
|
||||
data->adjust_tz = true;
|
||||
if (!rc)
|
||||
data->unknown_nlink = true;
|
||||
} else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) {
|
||||
/* Path with non-UNICODE wildcard character cannot exist. */
|
||||
rc = -ENOENT;
|
||||
@@ -893,8 +897,10 @@ static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms
|
||||
else
|
||||
rc = CIFS_open(xid, oparms, oplock, &fi);
|
||||
|
||||
if (!rc && data)
|
||||
if (!rc && data) {
|
||||
move_cifs_info_to_smb2(&data->fi, &fi);
|
||||
data->unknown_nlink = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -576,6 +576,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
idata->fi.EndOfFile = create_rsp->EndofFile;
|
||||
if (le32_to_cpu(idata->fi.NumberOfLinks) == 0)
|
||||
idata->fi.NumberOfLinks = cpu_to_le32(1); /* dummy value */
|
||||
idata->unknown_nlink = true;
|
||||
idata->fi.DeletePending = 0; /* successful open = not delete pending */
|
||||
idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user