summaryrefslogtreecommitdiff
path: root/fs/smb/client
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client')
-rw-r--r--fs/smb/client/.gitignore4
-rw-r--r--fs/smb/client/Kconfig26
-rw-r--r--fs/smb/client/Makefile50
-rw-r--r--fs/smb/client/cached_dir.c220
-rw-r--r--fs/smb/client/cached_dir.h71
-rw-r--r--fs/smb/client/cifs_debug.c281
-rw-r--r--fs/smb/client/cifs_debug.h5
-rw-r--r--fs/smb/client/cifs_fs_sb.h2
-rw-r--r--fs/smb/client/cifs_ioctl.h10
-rw-r--r--fs/smb/client/cifs_spnego.c66
-rw-r--r--fs/smb/client/cifs_spnego.h6
-rw-r--r--fs/smb/client/cifs_swn.c22
-rw-r--r--fs/smb/client/cifs_swn.h10
-rw-r--r--fs/smb/client/cifs_unicode.c19
-rw-r--r--fs/smb/client/cifs_unicode.h32
-rw-r--r--fs/smb/client/cifsacl.c159
-rw-r--r--fs/smb/client/cifsencrypt.c465
-rw-r--r--fs/smb/client/cifsfs.c221
-rw-r--r--fs/smb/client/cifsfs.h136
-rw-r--r--fs/smb/client/cifsglob.h513
-rw-r--r--fs/smb/client/cifspdu.h2712
-rw-r--r--fs/smb/client/cifsproto.h945
-rw-r--r--fs/smb/client/cifssmb.c1316
-rw-r--r--fs/smb/client/compress.c102
-rw-r--r--fs/smb/client/compress.h20
-rw-r--r--fs/smb/client/compress/lz77.c274
-rw-r--r--fs/smb/client/compress/lz77.h32
-rw-r--r--fs/smb/client/connect.c709
-rw-r--r--fs/smb/client/dfs.h5
-rw-r--r--fs/smb/client/dfs_cache.c61
-rw-r--r--fs/smb/client/dfs_cache.h19
-rw-r--r--fs/smb/client/dir.c514
-rw-r--r--fs/smb/client/dns_resolve.h8
-rw-r--r--fs/smb/client/file.c513
-rw-r--r--fs/smb/client/fs_context.c396
-rw-r--r--fs/smb/client/fs_context.h85
-rw-r--r--fs/smb/client/fscache.h17
-rw-r--r--fs/smb/client/gen_smb1_mapping124
-rw-r--r--fs/smb/client/gen_smb2_mapping86
-rw-r--r--fs/smb/client/inode.c500
-rw-r--r--fs/smb/client/ioctl.c10
-rw-r--r--fs/smb/client/link.c81
-rw-r--r--fs/smb/client/misc.c478
-rw-r--r--fs/smb/client/namespace.c4
-rw-r--r--fs/smb/client/netlink.h4
-rw-r--r--fs/smb/client/netmisc.c819
-rw-r--r--fs/smb/client/nterr.c683
-rw-r--r--fs/smb/client/nterr.h1071
-rw-r--r--fs/smb/client/ntlmssp.h23
-rw-r--r--fs/smb/client/readdir.c132
-rw-r--r--fs/smb/client/reparse.c135
-rw-r--r--fs/smb/client/reparse.h28
-rw-r--r--fs/smb/client/rfc1002pdu.h8
-rw-r--r--fs/smb/client/sess.c1043
-rw-r--r--fs/smb/client/smb1debug.c25
-rw-r--r--fs/smb/client/smb1encrypt.c140
-rw-r--r--fs/smb/client/smb1maperror.c286
-rw-r--r--fs/smb/client/smb1maperror_test.c77
-rw-r--r--fs/smb/client/smb1misc.c189
-rw-r--r--fs/smb/client/smb1ops.c715
-rw-r--r--fs/smb/client/smb1pdu.h2345
-rw-r--r--fs/smb/client/smb1proto.h350
-rw-r--r--fs/smb/client/smb1session.c995
-rw-r--r--fs/smb/client/smb1transport.c568
-rw-r--r--fs/smb/client/smb2file.c40
-rw-r--r--fs/smb/client/smb2glob.h15
-rw-r--r--fs/smb/client/smb2inode.c669
-rw-r--r--fs/smb/client/smb2maperror.c2507
-rw-r--r--fs/smb/client/smb2maperror_test.c49
-rw-r--r--fs/smb/client/smb2misc.c111
-rw-r--r--fs/smb/client/smb2ops.c853
-rw-r--r--fs/smb/client/smb2pdu.c834
-rw-r--r--fs/smb/client/smb2pdu.h115
-rw-r--r--fs/smb/client/smb2proto.h501
-rw-r--r--fs/smb/client/smb2transport.c348
-rw-r--r--fs/smb/client/smbdirect.c2530
-rw-r--r--fs/smb/client/smbdirect.h274
-rw-r--r--fs/smb/client/smbencrypt.c1
-rw-r--r--fs/smb/client/smberr.h415
-rw-r--r--fs/smb/client/trace.c2
-rw-r--r--fs/smb/client/trace.h444
-rw-r--r--fs/smb/client/transport.c816
-rw-r--r--fs/smb/client/xattr.c10
83 files changed, 14013 insertions, 17486 deletions
diff --git a/fs/smb/client/.gitignore b/fs/smb/client/.gitignore
new file mode 100644
index 000000000000..66e6e2ade0bd
--- /dev/null
+++ b/fs/smb/client/.gitignore
@@ -0,0 +1,4 @@
+smb1_mapping_table.c
+smb1_err_dos_map.c
+smb1_err_srv_map.c
+smb2_mapping_table.c
diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig
index 9f05f94e265a..2b7db5fb0fd9 100644
--- a/fs/smb/client/Kconfig
+++ b/fs/smb/client/Kconfig
@@ -5,16 +5,15 @@ config CIFS
select NLS
select NLS_UCS2_UTILS
select CRYPTO
- select CRYPTO_MD5
- select CRYPTO_SHA256
- select CRYPTO_SHA512
- select CRYPTO_CMAC
- select CRYPTO_HMAC
select CRYPTO_AEAD2
select CRYPTO_CCM
select CRYPTO_GCM
- select CRYPTO_ECB
select CRYPTO_AES
+ select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_ARC4
+ select CRYPTO_LIB_MD5
+ select CRYPTO_LIB_SHA256
+ select CRYPTO_LIB_SHA512
select KEYS
select DNS_RESOLVER
select ASN1
@@ -181,7 +180,9 @@ if CIFS
config CIFS_SMB_DIRECT
bool "SMB Direct support"
- depends on CIFS=m && INFINIBAND && INFINIBAND_ADDR_TRANS || CIFS=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y
+ depends on CIFS && INFINIBAND && INFINIBAND_ADDR_TRANS
+ depends on CIFS=m || INFINIBAND=y
+ select SMBDIRECT
help
Enables SMB Direct support for SMB 3.0, 3.02 and 3.1.1.
SMB Direct allows transferring SMB packets over RDMA. If unsure,
@@ -217,4 +218,15 @@ config CIFS_COMPRESSION
Say Y here if you want SMB traffic to be compressed.
If unsure, say N.
+config SMB1_KUNIT_TESTS
+ tristate "KUnit tests for SMB1"
+ depends on SMB_KUNIT_TESTS && CIFS_ALLOW_INSECURE_LEGACY
+ default SMB_KUNIT_TESTS
+ help
+ This builds the SMB1-specific KUnit tests.
+
+ These tests are only enabled when legacy insecure SMB1 support
+ (CIFS_ALLOW_INSECURE_LEGACY) is enabled.
+
+ If unsure, say N.
endif
diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 22023e30915b..6e83b5204699 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_CIFS) += cifs.o
cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
inode.o link.o misc.o netmisc.o smbencrypt.o transport.o \
- cached_dir.o cifs_unicode.o nterr.o cifsencrypt.o \
+ cached_dir.o cifs_unicode.o cifsencrypt.o \
readdir.o ioctl.o sess.o export.o unc.o winucase.o \
smb2ops.o smb2maperror.o smb2transport.o \
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
@@ -32,6 +32,52 @@ cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
-cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o cifssmb.o
+cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += \
+ cifssmb.o \
+ smb1debug.o \
+ smb1encrypt.o \
+ smb1maperror.o \
+ smb1misc.o \
+ smb1ops.o \
+ smb1session.o \
+ smb1transport.o
cifs-$(CONFIG_CIFS_COMPRESSION) += compress.o compress/lz77.o
+
+ifneq ($(CONFIG_CIFS_ALLOW_INSECURE_LEGACY),)
+#
+# Build the SMB1 error mapping tables from nterr.h and smberr.h
+#
+smb1-gen-y := smb1_mapping_table.c \
+ smb1_err_dos_map.c \
+ smb1_err_srv_map.c
+
+$(obj)/smb1_mapping_table.c: $(src)/nterr.h $(src)/gen_smb1_mapping FORCE
+ $(call if_changed,gen_smb1_mapping)
+
+$(obj)/smb1_err_%.c: $(src)/smberr.h $(src)/gen_smb1_mapping FORCE
+ $(call if_changed,gen_smb1_mapping)
+
+$(obj)/smb1maperror.o: $(addprefix $(obj)/, $(smb1-gen-y))
+
+quiet_cmd_gen_smb1_mapping = GEN $@
+ cmd_gen_smb1_mapping = perl $(src)/gen_smb1_mapping $< $@
+endif
+
+#
+# Build the SMB2 error mapping table from smb2status.h
+#
+$(obj)/smb2_mapping_table.c: $(src)/../common/smb2status.h \
+ $(src)/gen_smb2_mapping FORCE
+ $(call if_changed,gen_smb2_mapping)
+
+$(obj)/smb2maperror.o: $(obj)/smb2_mapping_table.c
+
+quiet_cmd_gen_smb2_mapping = GEN $@
+ cmd_gen_smb2_mapping = perl $(src)/gen_smb2_mapping $< $@
+
+obj-$(CONFIG_SMB1_KUNIT_TESTS) += smb1maperror_test.o
+obj-$(CONFIG_SMB_KUNIT_TESTS) += smb2maperror_test.o
+
+# Let Kbuild handle tracking and cleaning
+targets += smb2_mapping_table.c $(smb1-gen-y)
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index fe738623cf1b..02791ec3c5a1 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -16,6 +16,7 @@ static struct cached_fid *init_cached_dir(const char *path);
static void free_cached_dir(struct cached_fid *cfid);
static void smb2_close_cached_fid(struct kref *ref);
static void cfids_laundromat_worker(struct work_struct *work);
+static void close_cached_dir_locked(struct cached_fid *cfid);
struct cached_dir_dentry {
struct list_head entry;
@@ -29,7 +30,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
{
struct cached_fid *cfid;
- spin_lock(&cfids->cfid_list_lock);
list_for_each_entry(cfid, &cfids->entries, entry) {
if (!strcmp(cfid->path, path)) {
/*
@@ -37,26 +37,20 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
* fully cached or it may be in the process of
* being deleted due to a lease break.
*/
- if (!cfid->time || !cfid->has_lease) {
- spin_unlock(&cfids->cfid_list_lock);
+ if (!is_valid_cached_dir(cfid))
return NULL;
- }
kref_get(&cfid->refcount);
- spin_unlock(&cfids->cfid_list_lock);
return cfid;
}
}
if (lookup_only) {
- spin_unlock(&cfids->cfid_list_lock);
return NULL;
}
if (cfids->num_entries >= max_cached_dirs) {
- spin_unlock(&cfids->cfid_list_lock);
return NULL;
}
cfid = init_cached_dir(path);
if (cfid == NULL) {
- spin_unlock(&cfids->cfid_list_lock);
return NULL;
}
cfid->cfids = cfids;
@@ -74,7 +68,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
*/
cfid->has_lease = true;
- spin_unlock(&cfids->cfid_list_lock);
return cfid;
}
@@ -109,7 +102,8 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
while (*s && *s != sep)
s++;
- child = lookup_positive_unlocked(p, dentry, s - p);
+ child = lookup_noperm_positive_unlocked(&QSTR_LEN(p, s - p),
+ dentry);
dput(dentry);
dentry = child;
} while (!IS_ERR(dentry));
@@ -124,7 +118,7 @@ static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
if (!*path)
return path;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH) &&
cifs_sb->prepath) {
len = strlen(cifs_sb->prepath) + 1;
if (unlikely(len > strlen(path)))
@@ -160,7 +154,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct cached_fid *cfid;
struct cached_fids *cfids;
const char *npath;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
+ __le32 lease_flags = 0;
if (cifs_sb->root == NULL)
return -ENOENT;
@@ -181,14 +176,16 @@ replay_again:
server = cifs_pick_channel(ses);
if (!server->ops->new_lease_key)
- return -EIO;
+ return smb_EIO(smb_eio_trace_no_lease_key);
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path)
return -ENOMEM;
+ spin_lock(&cfids->cfid_list_lock);
cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs);
if (cfid == NULL) {
+ spin_unlock(&cfids->cfid_list_lock);
kfree(utf16_path);
return -ENOENT;
}
@@ -197,8 +194,8 @@ replay_again:
* Otherwise, it is either a new entry or laundromat worker removed it
* from @cfids->entries. Caller will put last reference if the latter.
*/
- spin_lock(&cfids->cfid_list_lock);
- if (cfid->has_lease && cfid->time) {
+ if (is_valid_cached_dir(cfid)) {
+ cfid->last_access_time = jiffies;
spin_unlock(&cfids->cfid_list_lock);
*ret_cfid = cfid;
kfree(utf16_path);
@@ -206,8 +203,10 @@ replay_again:
}
spin_unlock(&cfids->cfid_list_lock);
+ pfid = &cfid->fid;
+
/*
- * Skip any prefix paths in @path as lookup_positive_unlocked() ends up
+ * Skip any prefix paths in @path as lookup_noperm_positive_unlocked() ends up
* calling ->lookup() which already adds those through
* build_path_from_dentry(). Also, do it earlier as we might reconnect
* below when trying to send compounded request and then potentially
@@ -227,6 +226,25 @@ replay_again:
rc = -ENOENT;
goto out;
}
+ if (dentry->d_parent && server->dialect >= SMB30_PROT_ID) {
+ struct cached_fid *parent_cfid;
+
+ spin_lock(&cfids->cfid_list_lock);
+ list_for_each_entry(parent_cfid, &cfids->entries, entry) {
+ if (parent_cfid->dentry == dentry->d_parent) {
+ cifs_dbg(FYI, "found a parent cached file handle\n");
+ if (is_valid_cached_dir(parent_cfid)) {
+ lease_flags
+ |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
+ memcpy(pfid->parent_lease_key,
+ parent_cfid->fid.lease_key,
+ SMB2_LEASE_KEY_SIZE);
+ }
+ break;
+ }
+ }
+ spin_unlock(&cfids->cfid_list_lock);
+ }
}
cfid->dentry = dentry;
cfid->tcon = tcon;
@@ -241,7 +259,6 @@ replay_again:
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
- pfid = &cfid->fid;
server->ops->new_lease_key(pfid);
memset(rqst, 0, sizeof(rqst));
@@ -261,6 +278,7 @@ replay_again:
FILE_READ_EA,
.disposition = FILE_OPEN,
.fid = pfid,
+ .lease_flags = lease_flags,
.replay = !!(retries),
};
@@ -286,6 +304,10 @@ replay_again:
smb2_set_related(&rqst[1]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
+
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
}
@@ -346,6 +368,7 @@ replay_again:
cfid->file_all_info_is_valid = true;
cfid->time = jiffies;
+ cfid->last_access_time = jiffies;
spin_unlock(&cfids->cfid_list_lock);
/* At this point the directory handle is fully cached */
rc = 0;
@@ -370,11 +393,11 @@ out:
* lease. Release one here, and the second below.
*/
cfid->has_lease = false;
- kref_put(&cfid->refcount, smb2_close_cached_fid);
+ close_cached_dir_locked(cfid);
}
spin_unlock(&cfids->cfid_list_lock);
- kref_put(&cfid->refcount, smb2_close_cached_fid);
+ close_cached_dir(cfid);
} else {
*ret_cfid = cfid;
atomic_inc(&tcon->num_remote_opens);
@@ -398,12 +421,18 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
if (cfids == NULL)
return -EOPNOTSUPP;
+ if (!dentry)
+ return -ENOENT;
+
spin_lock(&cfids->cfid_list_lock);
list_for_each_entry(cfid, &cfids->entries, entry) {
- if (dentry && cfid->dentry == dentry) {
+ if (cfid->dentry == dentry) {
+ if (!is_valid_cached_dir(cfid))
+ break;
cifs_dbg(FYI, "found a cached file handle by dentry\n");
kref_get(&cfid->refcount);
*ret_cfid = cfid;
+ cfid->last_access_time = jiffies;
spin_unlock(&cfids->cfid_list_lock);
return 0;
}
@@ -414,12 +443,14 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
static void
smb2_close_cached_fid(struct kref *ref)
+__releases(&cfid->cfids->cfid_list_lock)
{
struct cached_fid *cfid = container_of(ref, struct cached_fid,
refcount);
int rc;
- spin_lock(&cfid->cfids->cfid_list_lock);
+ lockdep_assert_held(&cfid->cfids->cfid_list_lock);
+
if (cfid->on_list) {
list_del(&cfid->entry);
cfid->on_list = false;
@@ -454,15 +485,49 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
spin_lock(&cfid->cfids->cfid_list_lock);
if (cfid->has_lease) {
cfid->has_lease = false;
- kref_put(&cfid->refcount, smb2_close_cached_fid);
+ close_cached_dir_locked(cfid);
}
spin_unlock(&cfid->cfids->cfid_list_lock);
close_cached_dir(cfid);
}
-
+/**
+ * close_cached_dir - drop a reference of a cached dir
+ *
+ * The release function will be called with cfid_list_lock held to remove the
+ * cached dirs from the list before any other thread can take another @cfid
+ * ref. Must not be called with cfid_list_lock held; use
+ * close_cached_dir_locked() called instead.
+ *
+ * @cfid: cached dir
+ */
void close_cached_dir(struct cached_fid *cfid)
{
+ lockdep_assert_not_held(&cfid->cfids->cfid_list_lock);
+ kref_put_lock(&cfid->refcount, smb2_close_cached_fid, &cfid->cfids->cfid_list_lock);
+}
+
+/**
+ * close_cached_dir_locked - put a reference of a cached dir with
+ * cfid_list_lock held
+ *
+ * Calling close_cached_dir() with cfid_list_lock held has the potential effect
+ * of causing a deadlock if the invariant of refcount >= 2 is false.
+ *
+ * This function is used in paths that hold cfid_list_lock and expect at least
+ * two references. If that invariant is violated, WARNs and returns without
+ * dropping a reference; the final put must still go through
+ * close_cached_dir().
+ *
+ * @cfid: cached dir
+ */
+static void close_cached_dir_locked(struct cached_fid *cfid)
+{
+ lockdep_assert_held(&cfid->cfids->cfid_list_lock);
+
+ if (WARN_ON(kref_read(&cfid->refcount) < 2))
+ return;
+
kref_put(&cfid->refcount, smb2_close_cached_fid);
}
@@ -491,13 +556,21 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
continue;
spin_lock(&cfids->cfid_list_lock);
list_for_each_entry(cfid, &cfids->entries, entry) {
- tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC);
- if (tmp_list == NULL)
- break;
- spin_lock(&cfid->fid_lock);
+ tmp_list = kmalloc_obj(*tmp_list, GFP_ATOMIC);
+ if (tmp_list == NULL) {
+ /*
+ * If the malloc() fails, we won't drop all
+ * dentries, and unmounting is likely to trigger
+ * a 'Dentry still in use' error.
+ */
+ cifs_tcon_dbg(VFS, "Out of memory while dropping dentries\n");
+ spin_unlock(&cfids->cfid_list_lock);
+ spin_unlock(&cifs_sb->tlink_tree_lock);
+ goto done;
+ }
+
tmp_list->dentry = cfid->dentry;
cfid->dentry = NULL;
- spin_unlock(&cfid->fid_lock);
list_add_tail(&tmp_list->entry, &entry);
}
@@ -505,6 +578,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
}
spin_unlock(&cifs_sb->tlink_tree_lock);
+done:
list_for_each_entry_safe(tmp_list, q, &entry, entry) {
list_del(&tmp_list->entry);
dput(tmp_list->dentry);
@@ -519,7 +593,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
* Invalidate all cached dirs when a TCON has been reset
* due to a session loss.
*/
-void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
+void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync)
{
struct cached_fids *cfids = tcon->cfids;
struct cached_fid *cfid, *q;
@@ -529,8 +603,8 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
/*
* Mark all the cfids as closed, and move them to the cfids->dying list.
- * They'll be cleaned up later by cfids_invalidation_worker. Take
- * a reference to each cfid during this process.
+ * They'll be cleaned up by laundromat. Take a reference to each cfid
+ * during this process.
*/
spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
@@ -547,12 +621,12 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
} else
kref_get(&cfid->refcount);
}
- /*
- * Queue dropping of the dentries once locks have been dropped
- */
- if (!list_empty(&cfids->dying))
- queue_work(cfid_put_wq, &cfids->invalidation_work);
spin_unlock(&cfids->cfid_list_lock);
+
+ /* run laundromat unconditionally now as there might have been previously queued work */
+ mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+ if (sync)
+ flush_delayed_work(&cfids->laundromat_work);
}
static void
@@ -564,7 +638,7 @@ cached_dir_offload_close(struct work_struct *work)
WARN_ON(cfid->on_list);
- kref_put(&cfid->refcount, smb2_close_cached_fid);
+ close_cached_dir(cfid);
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
}
@@ -579,18 +653,13 @@ static void cached_dir_put_work(struct work_struct *work)
{
struct cached_fid *cfid = container_of(work, struct cached_fid,
put_work);
- struct dentry *dentry;
-
- spin_lock(&cfid->fid_lock);
- dentry = cfid->dentry;
+ dput(cfid->dentry);
cfid->dentry = NULL;
- spin_unlock(&cfid->fid_lock);
- dput(dentry);
queue_work(serverclose_wq, &cfid->close_work);
}
-int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
+bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
{
struct cached_fids *cfids = tcon->cfids;
struct cached_fid *cfid;
@@ -630,7 +699,7 @@ static struct cached_fid *init_cached_dir(const char *path)
{
struct cached_fid *cfid;
- cfid = kzalloc(sizeof(*cfid), GFP_ATOMIC);
+ cfid = kzalloc_obj(*cfid, GFP_ATOMIC);
if (!cfid)
return NULL;
cfid->path = kstrdup(path, GFP_ATOMIC);
@@ -644,7 +713,6 @@ static struct cached_fid *init_cached_dir(const char *path)
INIT_LIST_HEAD(&cfid->entry);
INIT_LIST_HEAD(&cfid->dirents.entries);
mutex_init(&cfid->dirents.de_mutex);
- spin_lock_init(&cfid->fid_lock);
kref_init(&cfid->refcount);
return cfid;
}
@@ -668,43 +736,41 @@ static void free_cached_dir(struct cached_fid *cfid)
kfree(dirent);
}
+ /* adjust tcon-level counters and reset per-dir accounting */
+ if (cfid->cfids) {
+ if (cfid->dirents.entries_count)
+ atomic_long_sub((long)cfid->dirents.entries_count,
+ &cfid->cfids->total_dirents_entries);
+ if (cfid->dirents.bytes_used) {
+ atomic64_sub((long long)cfid->dirents.bytes_used,
+ &cfid->cfids->total_dirents_bytes);
+ atomic64_sub((long long)cfid->dirents.bytes_used,
+ &cifs_dircache_bytes_used);
+ }
+ }
+ cfid->dirents.entries_count = 0;
+ cfid->dirents.bytes_used = 0;
+
kfree(cfid->path);
cfid->path = NULL;
kfree(cfid);
}
-static void cfids_invalidation_worker(struct work_struct *work)
-{
- struct cached_fids *cfids = container_of(work, struct cached_fids,
- invalidation_work);
- struct cached_fid *cfid, *q;
- LIST_HEAD(entry);
-
- spin_lock(&cfids->cfid_list_lock);
- /* move cfids->dying to the local list */
- list_cut_before(&entry, &cfids->dying, &cfids->dying);
- spin_unlock(&cfids->cfid_list_lock);
-
- list_for_each_entry_safe(cfid, q, &entry, entry) {
- list_del(&cfid->entry);
- /* Drop the ref-count acquired in invalidate_all_cached_dirs */
- kref_put(&cfid->refcount, smb2_close_cached_fid);
- }
-}
-
static void cfids_laundromat_worker(struct work_struct *work)
{
struct cached_fids *cfids;
struct cached_fid *cfid, *q;
- struct dentry *dentry;
LIST_HEAD(entry);
cfids = container_of(work, struct cached_fids, laundromat_work.work);
spin_lock(&cfids->cfid_list_lock);
+ /* move cfids->dying to the local list */
+ list_cut_before(&entry, &cfids->dying, &cfids->dying);
+
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
- if (cfid->time &&
- time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) {
+ if (cfid->last_access_time &&
+ time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) {
cfid->on_list = false;
list_move(&cfid->entry, &entry);
cfids->num_entries--;
@@ -723,25 +789,22 @@ static void cfids_laundromat_worker(struct work_struct *work)
list_for_each_entry_safe(cfid, q, &entry, entry) {
list_del(&cfid->entry);
- spin_lock(&cfid->fid_lock);
- dentry = cfid->dentry;
+ dput(cfid->dentry);
cfid->dentry = NULL;
- spin_unlock(&cfid->fid_lock);
- dput(dentry);
if (cfid->is_open) {
- spin_lock(&cifs_tcp_ses_lock);
+ spin_lock(&cfid->tcon->tc_lock);
++cfid->tcon->tc_count;
trace_smb3_tcon_ref(cfid->tcon->debug_id, cfid->tcon->tc_count,
netfs_trace_tcon_ref_get_cached_laundromat);
- spin_unlock(&cifs_tcp_ses_lock);
+ spin_unlock(&cfid->tcon->tc_lock);
queue_work(serverclose_wq, &cfid->close_work);
} else
/*
* Drop the ref-count from above, either the lease-ref (if there
* was one) or the extra one acquired.
*/
- kref_put(&cfid->refcount, smb2_close_cached_fid);
+ close_cached_dir(cfid);
}
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
dir_cache_timeout * HZ);
@@ -751,18 +814,20 @@ struct cached_fids *init_cached_dirs(void)
{
struct cached_fids *cfids;
- cfids = kzalloc(sizeof(*cfids), GFP_KERNEL);
+ cfids = kzalloc_obj(*cfids);
if (!cfids)
return NULL;
spin_lock_init(&cfids->cfid_list_lock);
INIT_LIST_HEAD(&cfids->entries);
INIT_LIST_HEAD(&cfids->dying);
- INIT_WORK(&cfids->invalidation_work, cfids_invalidation_worker);
INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
dir_cache_timeout * HZ);
+ atomic_long_set(&cfids->total_dirents_entries, 0);
+ atomic64_set(&cfids->total_dirents_bytes, 0);
+
return cfids;
}
@@ -779,7 +844,6 @@ void free_cached_dirs(struct cached_fids *cfids)
return;
cancel_delayed_work_sync(&cfids->laundromat_work);
- cancel_work_sync(&cfids->invalidation_work);
spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index 1dfe79d947a6..fc756836da95 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -14,40 +14,44 @@ struct cached_dirent {
char *name;
int namelen;
loff_t pos;
-
struct cifs_fattr fattr;
};
struct cached_dirents {
bool is_valid:1;
bool is_failed:1;
- struct dir_context *ctx; /*
- * Only used to make sure we only take entries
- * from a single context. Never dereferenced.
- */
+ struct file *file; /*
+ * Used to associate the cache with a single
+ * open file instance.
+ */
struct mutex de_mutex;
- int pos; /* Expected ctx->pos */
+ loff_t pos; /* Expected ctx->pos */
struct list_head entries;
+ /* accounting for cached entries in this directory */
+ unsigned long entries_count;
+ unsigned long bytes_used;
};
struct cached_fid {
struct list_head entry;
struct cached_fids *cfids;
const char *path;
- bool has_lease:1;
- bool is_open:1;
- bool on_list:1;
- bool file_all_info_is_valid:1;
+ bool has_lease;
+ bool is_open;
+ bool on_list;
+ bool file_all_info_is_valid;
unsigned long time; /* jiffies of when lease was taken */
+ unsigned long last_access_time; /* jiffies of when last accessed */
struct kref refcount;
struct cifs_fid fid;
- spinlock_t fid_lock;
struct cifs_tcon *tcon;
struct dentry *dentry;
struct work_struct put_work;
struct work_struct close_work;
- struct smb2_file_all_info file_all_info;
struct cached_dirents dirents;
+
+ /* Must be last as it ends in a flexible-array member. */
+ struct smb2_file_all_info file_all_info;
};
/* default MAX_CACHED_FIDS is 16 */
@@ -60,26 +64,33 @@ struct cached_fids {
int num_entries;
struct list_head entries;
struct list_head dying;
- struct work_struct invalidation_work;
struct delayed_work laundromat_work;
+ /* aggregate accounting for all cached dirents under this tcon */
+ atomic_long_t total_dirents_entries;
+ atomic64_t total_dirents_bytes;
};
-extern struct cached_fids *init_cached_dirs(void);
-extern void free_cached_dirs(struct cached_fids *cfids);
-extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
- const char *path,
- struct cifs_sb_info *cifs_sb,
- bool lookup_only, struct cached_fid **cfid);
-extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
- struct dentry *dentry,
- struct cached_fid **cfid);
-extern void close_cached_dir(struct cached_fid *cfid);
-extern void drop_cached_dir_by_name(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *name,
- struct cifs_sb_info *cifs_sb);
-extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
-extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
-extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
+/* Module-wide directory cache accounting (defined in cifsfs.c) */
+extern atomic64_t cifs_dircache_bytes_used; /* bytes across all mounts */
+
+static inline bool
+is_valid_cached_dir(struct cached_fid *cfid)
+{
+ return cfid->time && cfid->has_lease;
+}
+
+struct cached_fids *init_cached_dirs(void);
+void free_cached_dirs(struct cached_fids *cfids);
+int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, const char *path,
+ struct cifs_sb_info *cifs_sb, bool lookup_only,
+ struct cached_fid **ret_cfid);
+int open_cached_dir_by_dentry(struct cifs_tcon *tcon, struct dentry *dentry,
+ struct cached_fid **ret_cfid);
+void close_cached_dir(struct cached_fid *cfid);
+void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
+void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
+void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync);
+bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
#endif /* _CACHED_DIR_H */
diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index e03c890de0a0..4ed4f55a0bb7 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <uapi/linux/ethtool.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -26,6 +25,7 @@
#include "smbdirect.h"
#endif
#include "cifs_swn.h"
+#include "cached_dir.h"
void
cifs_dump_mem(char *label, void *data, int length)
@@ -35,21 +35,6 @@ cifs_dump_mem(char *label, void *data, int length)
data, length, true);
}
-void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
-{
-#ifdef CONFIG_CIFS_DEBUG2
- struct smb_hdr *smb = buf;
-
- cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d Wct: %d\n",
- smb->Command, smb->Status.CifsError, smb->Flags,
- smb->Flags2, smb->Mid, smb->Pid, smb->WordCount);
- if (!server->ops->check_message(buf, server->total_read, server)) {
- cifs_dbg(VFS, "smb buf %p len %u\n", smb,
- server->ops->calc_smb_size(smb));
- }
-#endif /* CONFIG_CIFS_DEBUG2 */
-}
-
void cifs_dump_mids(struct TCP_Server_Info *server)
{
#ifdef CONFIG_CIFS_DEBUG2
@@ -59,7 +44,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
return;
cifs_dbg(VFS, "Dump pending requests:\n");
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n",
mid_entry->mid_state,
@@ -77,12 +62,12 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n",
mid_entry->multiRsp, mid_entry->multiEnd);
if (mid_entry->resp_buf) {
- cifs_dump_detail(mid_entry->resp_buf, server);
- cifs_dump_mem("existing buf: ",
- mid_entry->resp_buf, 62);
+ server->ops->dump_detail(mid_entry->resp_buf,
+ mid_entry->response_pdu_len, server);
+ cifs_dump_mem("existing buf: ", mid_entry->resp_buf, 62);
}
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
#endif /* CONFIG_CIFS_DEBUG2 */
}
@@ -238,14 +223,18 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
struct cifs_ses *ses;
struct cifs_tcon *tcon;
struct cifsFileInfo *cfile;
+ struct inode *inode;
+ struct cifsInodeInfo *cinode;
+ char lease[4];
+ int n;
seq_puts(m, "# Version:1\n");
seq_puts(m, "# Format:\n");
seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
#ifdef CONFIG_CIFS_DEBUG2
- seq_printf(m, " <filename> <mid>\n");
+ seq_puts(m, " <filename> <lease> <lease-key> <mid>\n");
#else
- seq_printf(m, " <filename>\n");
+ seq_puts(m, " <filename> <lease> <lease-key>\n");
#endif /* CIFS_DEBUG2 */
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
@@ -265,11 +254,37 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
cfile->pid,
from_kuid(&init_user_ns, cfile->uid),
cfile->dentry);
+
+ /* Append lease/oplock caching state as RHW letters */
+ inode = d_inode(cfile->dentry);
+ cinode = NULL;
+ n = 0;
+ if (inode) {
+ cinode = CIFS_I(inode);
+ if (CIFS_CACHE_READ(cinode))
+ lease[n++] = 'R';
+ if (CIFS_CACHE_HANDLE(cinode))
+ lease[n++] = 'H';
+ if (CIFS_CACHE_WRITE(cinode))
+ lease[n++] = 'W';
+ }
+ lease[n] = '\0';
+ seq_puts(m, " ");
+ if (n)
+ seq_printf(m, "%s", lease);
+ else
+ seq_puts(m, "NONE");
+
+ seq_puts(m, " ");
+ if (cinode && cinode->lease_granted)
+ seq_printf(m, "%pUl", cinode->lease_key);
+ else
+ seq_puts(m, "-");
+
#ifdef CONFIG_CIFS_DEBUG2
- seq_printf(m, " %llu\n", cfile->fid.mid);
-#else
+ seq_printf(m, " %llu", cfile->fid.mid);
+#endif /* CONFIG_CIFS_DEBUG2 */
seq_printf(m, "\n");
-#endif /* CIFS_DEBUG2 */
}
spin_unlock(&tcon->open_file_lock);
}
@@ -280,6 +295,112 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
return 0;
}
+static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
+{
+ struct list_head *stmp, *tmp, *tmp1;
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cached_fids *cfids;
+ struct cached_fid *cfid;
+ LIST_HEAD(entry);
+
+ seq_puts(m, "# Version:1\n");
+#ifdef CONFIG_CIFS_DEBUG
+ seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n");
+#endif /* CONFIG_CIFS_DEBUG */
+ seq_puts(m, "# Format:\n");
+ seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n");
+
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(stmp, &cifs_tcp_ses_list) {
+ server = list_entry(stmp, struct TCP_Server_Info,
+ tcp_ses_list);
+ list_for_each(tmp, &server->smb_ses_list) {
+ ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+ list_for_each(tmp1, &ses->tcon_list) {
+ tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+ cfids = tcon->cfids;
+ if (!cfids)
+ continue;
+ spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
+ seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
+ cfids->num_entries,
+ (unsigned long)atomic_long_read(&cfids->total_dirents_entries),
+ (unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
+ list_for_each_entry(cfid, &cfids->entries, entry) {
+ seq_printf(m, "0x%x 0x%llx 0x%llx ",
+ tcon->tid,
+ ses->Suid,
+ cfid->fid.persistent_fid);
+ if (cfid->has_lease)
+ seq_printf(m, "%pUl ", cfid->fid.lease_key);
+ else
+ seq_puts(m, "- ");
+ seq_printf(m, "%s", cfid->path);
+ if (cfid->file_all_info_is_valid)
+ seq_printf(m, "\tvalid file info");
+ if (cfid->dirents.is_valid)
+ seq_printf(m, ", valid dirents");
+ if (!list_empty(&cfid->dirents.entries))
+ seq_printf(m, ", dirents: %lu entries, %lu bytes",
+ cfid->dirents.entries_count, cfid->dirents.bytes_used);
+ seq_printf(m, "\n");
+ }
+ spin_unlock(&cfids->cfid_list_lock);
+ }
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ seq_putc(m, '\n');
+ return 0;
+}
+
+#ifdef CONFIG_CIFS_DEBUG
+static int cifs_debug_dirs_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_debug_dirs_proc_show, NULL);
+}
+
+/* Drop all cached directory entries across all CIFS mounts. */
+static ssize_t cifs_debug_dirs_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int rc, v;
+
+ rc = kstrtoint_from_user(buffer, count, 10, &v);
+ if (rc)
+ return rc;
+
+ if (v == 0) {
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
+ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+ if (cifs_ses_exiting(ses))
+ continue;
+ list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
+ invalidate_all_cached_dirs(tcon, false);
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ }
+
+ return count;
+}
+
+static const struct proc_ops cifs_debug_dirs_proc_ops = {
+ .proc_open = cifs_debug_dirs_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = cifs_debug_dirs_proc_write,
+};
+#endif /* CONFIG_CIFS_DEBUG */
+
static __always_inline const char *compression_alg_str(__le16 alg)
{
switch (alg) {
@@ -298,6 +419,22 @@ static __always_inline const char *compression_alg_str(__le16 alg)
}
}
+static __always_inline const char *cipher_alg_str(__le16 cipher)
+{
+ switch (cipher) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ return "AES128-CCM";
+ case SMB2_ENCRYPTION_AES128_GCM:
+ return "AES128-GCM";
+ case SMB2_ENCRYPTION_AES256_CCM:
+ return "AES256-CCM";
+ case SMB2_ENCRYPTION_AES256_GCM:
+ return "AES256-GCM";
+ default:
+ return "UNKNOWN";
+ }
+}
+
static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{
struct mid_q_entry *mid_entry;
@@ -376,70 +513,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, "\nClientGUID: %pUL", server->client_guid);
spin_unlock(&server->srv_lock);
#ifdef CONFIG_CIFS_SMB_DIRECT
- if (!server->rdma)
- goto skip_rdma;
-
- if (!server->smbd_conn) {
- seq_printf(m, "\nSMBDirect transport not available");
- goto skip_rdma;
- }
-
- seq_printf(m, "\nSMBDirect (in hex) protocol version: %x "
- "transport status: %x",
- server->smbd_conn->protocol,
- server->smbd_conn->transport_status);
- seq_printf(m, "\nConn receive_credit_max: %x "
- "send_credit_target: %x max_send_size: %x",
- server->smbd_conn->receive_credit_max,
- server->smbd_conn->send_credit_target,
- server->smbd_conn->max_send_size);
- seq_printf(m, "\nConn max_fragmented_recv_size: %x "
- "max_fragmented_send_size: %x max_receive_size:%x",
- server->smbd_conn->max_fragmented_recv_size,
- server->smbd_conn->max_fragmented_send_size,
- server->smbd_conn->max_receive_size);
- seq_printf(m, "\nConn keep_alive_interval: %x "
- "max_readwrite_size: %x rdma_readwrite_threshold: %x",
- server->smbd_conn->keep_alive_interval,
- server->smbd_conn->max_readwrite_size,
- server->smbd_conn->rdma_readwrite_threshold);
- seq_printf(m, "\nDebug count_get_receive_buffer: %x "
- "count_put_receive_buffer: %x count_send_empty: %x",
- server->smbd_conn->count_get_receive_buffer,
- server->smbd_conn->count_put_receive_buffer,
- server->smbd_conn->count_send_empty);
- seq_printf(m, "\nRead Queue count_reassembly_queue: %x "
- "count_enqueue_reassembly_queue: %x "
- "count_dequeue_reassembly_queue: %x "
- "fragment_reassembly_remaining: %x "
- "reassembly_data_length: %x "
- "reassembly_queue_length: %x",
- server->smbd_conn->count_reassembly_queue,
- server->smbd_conn->count_enqueue_reassembly_queue,
- server->smbd_conn->count_dequeue_reassembly_queue,
- server->smbd_conn->fragment_reassembly_remaining,
- server->smbd_conn->reassembly_data_length,
- server->smbd_conn->reassembly_queue_length);
- seq_printf(m, "\nCurrent Credits send_credits: %x "
- "receive_credits: %x receive_credit_target: %x",
- atomic_read(&server->smbd_conn->send_credits),
- atomic_read(&server->smbd_conn->receive_credits),
- server->smbd_conn->receive_credit_target);
- seq_printf(m, "\nPending send_pending: %x ",
- atomic_read(&server->smbd_conn->send_pending));
- seq_printf(m, "\nReceive buffers count_receive_queue: %x "
- "count_empty_packet_queue: %x",
- server->smbd_conn->count_receive_queue,
- server->smbd_conn->count_empty_packet_queue);
- seq_printf(m, "\nMR responder_resources: %x "
- "max_frmr_depth: %x mr_type: %x",
- server->smbd_conn->responder_resources,
- server->smbd_conn->max_frmr_depth,
- server->smbd_conn->mr_type);
- seq_printf(m, "\nMR mr_ready_count: %x mr_used_count: %x",
- atomic_read(&server->smbd_conn->mr_ready_count),
- atomic_read(&server->smbd_conn->mr_used_count));
-skip_rdma:
+ smbd_debug_proc_show(server, m);
#endif
seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
server->credits,
@@ -487,6 +561,11 @@ skip_rdma:
else
seq_puts(m, "disabled (not supported by this server)");
+ /* Show negotiated encryption cipher, even if not required */
+ seq_puts(m, "\nEncryption: ");
+ if (server->cipher_type)
+ seq_printf(m, "Negotiated cipher (%s)", cipher_alg_str(server->cipher_type));
+
seq_printf(m, "\n\n\tSessions: ");
i = 0;
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
@@ -524,12 +603,8 @@ skip_rdma:
/* dump session id helpful for use with network trace */
seq_printf(m, " SessionId: 0x%llx", ses->Suid);
- if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) {
+ if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
seq_puts(m, " encrypted");
- /* can help in debugging to show encryption type */
- if (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
- seq_puts(m, "(gcm256)");
- }
if (ses->sign)
seq_puts(m, " signed");
@@ -618,7 +693,7 @@ skip_rdma:
seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
chan_server->conn_id);
- spin_lock(&chan_server->mid_lock);
+ spin_lock(&chan_server->mid_queue_lock);
list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
mid_entry->mid_state,
@@ -627,7 +702,7 @@ skip_rdma:
mid_entry->callback_data,
mid_entry->mid);
}
- spin_unlock(&chan_server->mid_lock);
+ spin_unlock(&chan_server->mid_queue_lock);
}
spin_unlock(&ses->chan_lock);
seq_puts(m, "\n--\n");
@@ -858,6 +933,11 @@ cifs_proc_init(void)
proc_create_single("open_files", 0400, proc_fs_cifs,
cifs_debug_files_proc_show);
+#ifdef CONFIG_CIFS_DEBUG
+ proc_create("open_dirs", 0600, proc_fs_cifs, &cifs_debug_dirs_proc_ops);
+#else /* CONFIG_CIFS_DEBUG */
+ proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show);
+#endif /* !CONFIG_CIFS_DEBUG */
proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops);
proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops);
proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);
@@ -902,6 +982,7 @@ cifs_proc_clean(void)
remove_proc_entry("DebugData", proc_fs_cifs);
remove_proc_entry("open_files", proc_fs_cifs);
+ remove_proc_entry("open_dirs", proc_fs_cifs);
remove_proc_entry("cifsFYI", proc_fs_cifs);
remove_proc_entry("traceSMB", proc_fs_cifs);
remove_proc_entry("Stats", proc_fs_cifs);
@@ -1100,7 +1181,7 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
if ((count < 1) || (count > 11))
return -EINVAL;
- memset(flags_string, 0, 12);
+ memset(flags_string, 0, sizeof(flags_string));
if (copy_from_user(flags_string, buffer, count))
return -EFAULT;
@@ -1206,11 +1287,11 @@ static const struct proc_ops cifs_mount_params_proc_ops = {
};
#else
-inline void cifs_proc_init(void)
+void cifs_proc_init(void)
{
}
-inline void cifs_proc_clean(void)
+void cifs_proc_clean(void)
{
}
#endif /* PROC_FS */
diff --git a/fs/smb/client/cifs_debug.h b/fs/smb/client/cifs_debug.h
index ce5cfd236fdb..00650929a133 100644
--- a/fs/smb/client/cifs_debug.h
+++ b/fs/smb/client/cifs_debug.h
@@ -15,10 +15,9 @@
#define pr_fmt(fmt) "CIFS: " fmt
void cifs_dump_mem(char *label, void *data, int length);
-void cifs_dump_detail(void *buf, struct TCP_Server_Info *ptcp_info);
-void cifs_dump_mids(struct TCP_Server_Info *);
+void cifs_dump_mids(struct TCP_Server_Info *server);
extern bool traceSMB; /* flag which enables the function below */
-void dump_smb(void *, int);
+void dump_smb(void *buf, int smb_buf_length);
#define CIFS_INFO 0x01
#define CIFS_RC 0x02
#define CIFS_TIMER 0x04
diff --git a/fs/smb/client/cifs_fs_sb.h b/fs/smb/client/cifs_fs_sb.h
index 5e8d163cb5f8..84e7e366b0ff 100644
--- a/fs/smb/client/cifs_fs_sb.h
+++ b/fs/smb/client/cifs_fs_sb.h
@@ -55,7 +55,7 @@ struct cifs_sb_info {
struct nls_table *local_nls;
struct smb3_fs_context *ctx;
atomic_t active;
- unsigned int mnt_cifs_flags;
+ atomic_t mnt_cifs_flags;
struct delayed_work prune_tlinks;
struct rcu_head rcu;
diff --git a/fs/smb/client/cifs_ioctl.h b/fs/smb/client/cifs_ioctl.h
index 26327442e383..147496ac9f9f 100644
--- a/fs/smb/client/cifs_ioctl.h
+++ b/fs/smb/client/cifs_ioctl.h
@@ -61,7 +61,7 @@ struct smb_query_info {
struct smb3_key_debug_info {
__u64 Suid;
__u16 cipher_type;
- __u8 auth_key[16]; /* SMB2_NTLMV2_SESSKEY_SIZE */
+ __u8 auth_key[SMB2_NTLMV2_SESSKEY_SIZE];
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
} __packed;
@@ -122,11 +122,3 @@ struct smb3_notify_info {
#define CIFS_GOING_FLAGS_DEFAULT 0x0 /* going down */
#define CIFS_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
#define CIFS_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
-
-static inline bool cifs_forced_shutdown(struct cifs_sb_info *sbi)
-{
- if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags)
- return true;
- else
- return false;
-}
diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c
index bc1c1e9b288a..3a41bbada04c 100644
--- a/fs/smb/client/cifs_spnego.c
+++ b/fs/smb/client/cifs_spnego.c
@@ -24,20 +24,14 @@ static const struct cred *spnego_cred;
static int
cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
- char *payload;
- int ret;
+ char *payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
- ret = -ENOMEM;
- payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
if (!payload)
- goto error;
+ return -ENOMEM;
/* attach the data */
key->payload.data[0] = payload;
- ret = 0;
-
-error:
- return ret;
+ return 0;
}
static void
@@ -96,7 +90,6 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
size_t desc_len;
struct key *spnego_key;
const char *hostname = server->hostname;
- const struct cred *saved_cred;
/* length of fields (with semicolons): ver=0xyz ip4=ipaddress
host=hostname sec=mechanism uid=0xFF user=username */
@@ -124,60 +117,49 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
dp = description;
/* start with version and hostname portion of UNC string */
spnego_key = ERR_PTR(-EINVAL);
- sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
- hostname);
- dp = description + strlen(description);
+ dp += sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
+ hostname);
/* add the server address */
if (server->dstaddr.ss_family == AF_INET)
- sprintf(dp, "ip4=%pI4", &sa->sin_addr);
+ dp += sprintf(dp, "ip4=%pI4", &sa->sin_addr);
else if (server->dstaddr.ss_family == AF_INET6)
- sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
+ dp += sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
else
goto out;
- dp = description + strlen(description);
-
/* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */
if (server->sec_kerberos)
- sprintf(dp, ";sec=krb5");
+ dp += sprintf(dp, ";sec=krb5");
else if (server->sec_mskerberos)
- sprintf(dp, ";sec=mskrb5");
+ dp += sprintf(dp, ";sec=mskrb5");
else if (server->sec_iakerb)
- sprintf(dp, ";sec=iakerb");
+ dp += sprintf(dp, ";sec=iakerb");
else {
cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
- sprintf(dp, ";sec=krb5");
+ dp += sprintf(dp, ";sec=krb5");
}
- dp = description + strlen(description);
- sprintf(dp, ";uid=0x%x",
- from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
+ dp += sprintf(dp, ";uid=0x%x",
+ from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
- dp = description + strlen(description);
- sprintf(dp, ";creduid=0x%x",
+ dp += sprintf(dp, ";creduid=0x%x",
from_kuid_munged(&init_user_ns, sesInfo->cred_uid));
- if (sesInfo->user_name) {
- dp = description + strlen(description);
- sprintf(dp, ";user=%s", sesInfo->user_name);
- }
+ if (sesInfo->user_name)
+ dp += sprintf(dp, ";user=%s", sesInfo->user_name);
- dp = description + strlen(description);
- sprintf(dp, ";pid=0x%x", current->pid);
+ dp += sprintf(dp, ";pid=0x%x", current->pid);
- if (sesInfo->upcall_target == UPTARGET_MOUNT) {
- dp = description + strlen(description);
- sprintf(dp, ";upcall_target=mount");
- } else {
- dp = description + strlen(description);
- sprintf(dp, ";upcall_target=app");
- }
+ if (sesInfo->upcall_target == UPTARGET_MOUNT)
+ dp += sprintf(dp, ";upcall_target=mount");
+ else
+ dp += sprintf(dp, ";upcall_target=app");
cifs_dbg(FYI, "key description = %s\n", description);
- saved_cred = override_creds(spnego_cred);
- spnego_key = request_key(&cifs_spnego_key_type, description, "");
- revert_creds(saved_cred);
+ scoped_with_creds(spnego_cred)
+ spnego_key = request_key(&cifs_spnego_key_type, description, "");
+ trace_smb3_kerberos_auth(server, sesInfo, PTR_ERR_OR_ZERO(spnego_key));
#ifdef CONFIG_CIFS_DEBUG2
if (cifsFYI && !IS_ERR(spnego_key)) {
diff --git a/fs/smb/client/cifs_spnego.h b/fs/smb/client/cifs_spnego.h
index e4d751b0c812..987768348624 100644
--- a/fs/smb/client/cifs_spnego.h
+++ b/fs/smb/client/cifs_spnego.h
@@ -27,10 +27,8 @@ struct cifs_spnego_msg {
uint8_t data[];
};
-#ifdef __KERNEL__
extern struct key_type cifs_spnego_key_type;
-extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo,
- struct TCP_Server_Info *server);
-#endif /* KERNEL */
+struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo,
+ struct TCP_Server_Info *server);
#endif /* _CIFS_SPNEGO_H */
diff --git a/fs/smb/client/cifs_swn.c b/fs/smb/client/cifs_swn.c
index 7233c6a7e6d7..9753a432d099 100644
--- a/fs/smb/client/cifs_swn.c
+++ b/fs/smb/client/cifs_swn.c
@@ -82,10 +82,8 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
int ret;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (skb == NULL) {
- ret = -ENOMEM;
- goto fail;
- }
+ if (!skb)
+ return -ENOMEM;
hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER);
if (hdr == NULL) {
@@ -172,7 +170,6 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
nlmsg_fail:
genlmsg_cancel(skb, hdr);
nlmsg_free(skb);
-fail:
return ret;
}
@@ -313,17 +310,15 @@ static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
reg = cifs_find_swn_reg(tcon);
if (!IS_ERR(reg)) {
kref_get(&reg->ref_count);
- mutex_unlock(&cifs_swnreg_idr_mutex);
- return reg;
+ goto unlock;
} else if (PTR_ERR(reg) != -EEXIST) {
- mutex_unlock(&cifs_swnreg_idr_mutex);
- return reg;
+ goto unlock;
}
- reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC);
+ reg = kmalloc_obj(struct cifs_swn_reg, GFP_ATOMIC);
if (reg == NULL) {
- mutex_unlock(&cifs_swnreg_idr_mutex);
- return ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto fail_unlock;
}
kref_init(&reg->ref_count);
@@ -354,7 +349,7 @@ static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT);
reg->tcon = tcon;
-
+unlock:
mutex_unlock(&cifs_swnreg_idr_mutex);
return reg;
@@ -365,6 +360,7 @@ fail_idr:
idr_remove(&cifs_swnreg_idr, reg->id);
fail:
kfree(reg);
+fail_unlock:
mutex_unlock(&cifs_swnreg_idr_mutex);
return ERR_PTR(ret);
}
diff --git a/fs/smb/client/cifs_swn.h b/fs/smb/client/cifs_swn.h
index 8a9d2a5c9077..955d07b69450 100644
--- a/fs/smb/client/cifs_swn.h
+++ b/fs/smb/client/cifs_swn.h
@@ -14,15 +14,15 @@ struct sk_buff;
struct genl_info;
#ifdef CONFIG_CIFS_SWN_UPCALL
-extern int cifs_swn_register(struct cifs_tcon *tcon);
+int cifs_swn_register(struct cifs_tcon *tcon);
-extern int cifs_swn_unregister(struct cifs_tcon *tcon);
+int cifs_swn_unregister(struct cifs_tcon *tcon);
-extern int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info);
+int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info);
-extern void cifs_swn_dump(struct seq_file *m);
+void cifs_swn_dump(struct seq_file *m);
-extern void cifs_swn_check(void);
+void cifs_swn_check(void);
static inline bool cifs_swn_set_server_dstaddr(struct TCP_Server_Info *server)
{
diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c
index 4cc6e0896fad..4a8a591f4bca 100644
--- a/fs/smb/client/cifs_unicode.c
+++ b/fs/smb/client/cifs_unicode.c
@@ -6,26 +6,12 @@
*/
#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/unaligned.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifs_debug.h"
-int cifs_remap(struct cifs_sb_info *cifs_sb)
-{
- int map_type;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
- map_type = SFM_MAP_UNI_RSVD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
- map_type = SFU_MAP_UNI_RSVD;
- else
- map_type = NO_MAP_UNI_RSVD;
-
- return map_type;
-}
-
/* Convert character using the SFU - "Services for Unix" remapping range */
static bool
convert_sfu_char(const __u16 src_char, char *target)
@@ -629,6 +615,9 @@ cifs_strndup_to_utf16(const char *src, const int maxlen, int *utf16_len,
int len;
__le16 *dst;
+ if (!src)
+ return NULL;
+
len = cifs_local_to_utf16_bytes(src, maxlen, cp);
len += 2; /* NULL */
dst = kmalloc(len, GFP_KERNEL);
diff --git a/fs/smb/client/cifs_unicode.h b/fs/smb/client/cifs_unicode.h
index e137a0dfbbe9..3e9cd9acf0a9 100644
--- a/fs/smb/client/cifs_unicode.h
+++ b/fs/smb/client/cifs_unicode.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/nls.h>
#include "../../nls/nls_ucs2_utils.h"
+#include "cifsglob.h"
/*
* Macs use an older "SFM" mapping of the symbols above. Fortunately it does
@@ -54,23 +55,32 @@
#define SFM_MAP_UNI_RSVD 1
#define SFU_MAP_UNI_RSVD 2
-#ifdef __KERNEL__
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
- const struct nls_table *cp, int map_type);
+ const struct nls_table *codepage, int map_type);
int cifs_utf16_bytes(const __le16 *from, int maxbytes,
const struct nls_table *codepage);
-int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
+int cifs_strtoUTF16(__le16 *to, const char *from, int len,
+ const struct nls_table *codepage);
char *cifs_strndup_from_utf16(const char *src, const int maxlen,
const bool is_unicode,
const struct nls_table *codepage);
-extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
- const struct nls_table *cp, int mapChars);
-extern int cifs_remap(struct cifs_sb_info *cifs_sb);
-extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
- int *utf16_len, const struct nls_table *cp,
- int remap);
-#endif
-
+int cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
+ const struct nls_table *cp, int map_chars);
+__le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
+ int *utf16_len, const struct nls_table *cp,
+ int remap);
wchar_t cifs_toupper(wchar_t in);
+static inline int cifs_remap(const struct cifs_sb_info *cifs_sb)
+{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_MAP_SFM_CHR)
+ return SFM_MAP_UNI_RSVD;
+ if (sbflags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ return SFU_MAP_UNI_RSVD;
+
+ return NO_MAP_UNI_RSVD;
+}
+
#endif /* _CIFS_UNICODE_H */
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 63b3b1290bed..ec5d47779304 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -17,7 +17,6 @@
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <keys/user-type.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsacl.h"
#include "cifsproto.h"
@@ -300,7 +299,7 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
__func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
goto out_revert_creds;
} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_malformed_sid_key, sidkey->datalen);
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
__func__, sidkey->datalen);
goto invalidate_key;
@@ -317,7 +316,8 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
if (ksid_size > sidkey->datalen) {
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_malformed_ksid_key,
+ ksid_size, sidkey->datalen);
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
__func__, sidkey->datalen, ksid_size);
goto invalidate_key;
@@ -339,7 +339,6 @@ int
sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
struct cifs_fattr *fattr, uint sidtype)
{
- int rc = 0;
struct key *sidkey;
char *sidstr;
const struct cred *saved_cred;
@@ -353,10 +352,11 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
__func__, psid->num_subauth);
- return -EIO;
+ return smb_EIO2(smb_eio_trace_sid_too_many_auth,
+ psid->num_subauth, SID_MAX_SUB_AUTHORITIES);
}
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_UID_FROM_ACL) ||
(cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
uint32_t unix_id;
bool is_group;
@@ -446,12 +446,12 @@ out_revert_creds:
* fails then we just fall back to using the ctx->linux_uid/linux_gid.
*/
got_valid_id:
- rc = 0;
if (sidtype == SIDOWNER)
fattr->cf_uid = fuid;
else
fattr->cf_gid = fgid;
- return rc;
+
+ return 0;
}
int
@@ -758,6 +758,77 @@ static void dump_ace(struct smb_ace *pace, char *end_of_acl)
}
#endif
+static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl)
+{
+ int i, ace_hdr_size, ace_size, min_ace_size;
+ u16 dacl_size, num_aces;
+ char *acl_base, *end_of_dacl;
+ struct smb_ace *pace;
+
+ if (!pdacl)
+ return 0;
+
+ if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ dacl_size = le16_to_cpu(pdacl->size);
+ if (dacl_size < sizeof(struct smb_acl) ||
+ end_of_acl < (char *)pdacl + dacl_size) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ num_aces = le16_to_cpu(pdacl->num_aces);
+ if (!num_aces)
+ return 0;
+
+ ace_hdr_size = offsetof(struct smb_ace, sid) +
+ offsetof(struct smb_sid, sub_auth);
+ min_ace_size = ace_hdr_size + sizeof(__le32);
+ if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ end_of_dacl = (char *)pdacl + dacl_size;
+ acl_base = (char *)pdacl;
+ ace_size = sizeof(struct smb_acl);
+
+ for (i = 0; i < num_aces; ++i) {
+ if (end_of_dacl - acl_base < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ pace = (struct smb_ace *)(acl_base + ace_size);
+ acl_base = (char *)pace;
+
+ if (end_of_dacl - acl_base < ace_hdr_size ||
+ pace->sid.num_subauth == 0 ||
+ pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
+ if (end_of_dacl - acl_base < ace_size ||
+ le16_to_cpu(pace->size) < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ ace_size = le16_to_cpu(pace->size);
+ if (end_of_dacl - acl_base < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct cifs_fattr *fattr, bool mode_from_special_sid)
@@ -777,12 +848,8 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
return;
}
- /* validate that we do not go past end of acl */
- if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
- end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
- cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ if (validate_dacl(pdacl, end_of_acl))
return;
- }
cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
@@ -800,38 +867,19 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
if (num_aces > 0) {
umode_t denied_mode = 0;
- if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
- (offsetof(struct smb_ace, sid) +
- offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
- return;
-
- ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *),
- GFP_KERNEL);
+ ppace = kmalloc_objs(struct smb_ace *, num_aces);
if (!ppace)
return;
for (i = 0; i < num_aces; ++i) {
- if (end_of_acl - acl_base < acl_size)
- break;
-
ppace[i] = (struct smb_ace *) (acl_base + acl_size);
- acl_base = (char *)ppace[i];
- acl_size = offsetof(struct smb_ace, sid) +
- offsetof(struct smb_sid, sub_auth);
-
- if (end_of_acl - acl_base < acl_size ||
- ppace[i]->sid.num_subauth == 0 ||
- ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
- (end_of_acl - acl_base <
- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
- (le16_to_cpu(ppace[i]->size) <
- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
- break;
#ifdef CONFIG_CIFS_DEBUG2
- dump_ace(ppace[i], end_of_acl);
+ dump_ace(ppace[i],
+ (char *)pdacl + le16_to_cpu(pdacl->size));
#endif
if (mode_from_special_sid &&
+ ppace[i]->sid.num_subauth >= 3 &&
(compare_sids(&(ppace[i]->sid),
&sid_unix_NFS_mode) == 0)) {
/*
@@ -871,6 +919,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
(void *)ppace[i],
sizeof(struct smb_ace)); */
+ acl_base = (char *)ppace[i];
acl_size = le16_to_cpu(ppace[i]->size);
}
@@ -1228,7 +1277,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
__u32 dacloffset;
if (pntsd == NULL)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
le32_to_cpu(pntsd->osidoffset));
@@ -1294,10 +1343,9 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
dacloffset = le32_to_cpu(pntsd->dacloffset);
if (dacloffset) {
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
- if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
- cifs_dbg(VFS, "Server returned illegal ACL size\n");
- return -EINVAL;
- }
+ rc = validate_dacl(dacl_ptr, end_of_acl);
+ if (rc)
+ return rc;
}
owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1332,8 +1380,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
if (uid_valid(uid)) { /* chown */
uid_t id;
- nowner_sid_ptr = kzalloc(sizeof(struct smb_sid),
- GFP_KERNEL);
+ nowner_sid_ptr = kzalloc_obj(struct smb_sid);
if (!nowner_sid_ptr) {
rc = -ENOMEM;
goto chown_chgrp_exit;
@@ -1361,8 +1408,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
}
if (gid_valid(gid)) { /* chgrp */
gid_t id;
- ngroup_sid_ptr = kzalloc(sizeof(struct smb_sid),
- GFP_KERNEL);
+ ngroup_sid_ptr = kzalloc_obj(struct smb_sid);
if (!ngroup_sid_ptr) {
rc = -ENOMEM;
goto chown_chgrp_exit;
@@ -1492,7 +1538,7 @@ struct smb_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL;
if (inode)
- open_file = find_readable_file(CIFS_I(inode), true);
+ open_file = find_readable_file(CIFS_I(inode), FIND_FSUID_ONLY);
if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen, info);
@@ -1615,7 +1661,8 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
struct smb_acl *dacl_ptr = NULL;
struct smb_ntsd *pntsd = NULL; /* acl obtained from server */
struct smb_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags;
struct tcon_link *tlink;
struct smb_version_operations *ops;
bool mode_from_sid, id_from_sid;
@@ -1646,15 +1693,9 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
return rc;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
- mode_from_sid = true;
- else
- mode_from_sid = false;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
- id_from_sid = true;
- else
- id_from_sid = false;
+ sbflags = cifs_sb_flags(cifs_sb);
+ mode_from_sid = sbflags & CIFS_MOUNT_MODE_FROM_SID;
+ id_from_sid = sbflags & CIFS_MOUNT_UID_FROM_ACL;
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
@@ -1670,6 +1711,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
dacloffset = le32_to_cpu(pntsd->dacloffset);
if (dacloffset) {
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
+ if (rc) {
+ kfree(pntsd);
+ cifs_put_tlink(tlink);
+ return rc;
+ }
if (mode_from_sid)
nsecdesclen +=
le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c
index 35892df7335c..34804e9842a8 100644
--- a/fs/smb/client/cifsencrypt.c
+++ b/fs/smb/client/cifsencrypt.c
@@ -11,7 +11,6 @@
#include <linux/fs.h>
#include <linux/slab.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifs_unicode.h"
@@ -22,246 +21,78 @@
#include <linux/highmem.h>
#include <linux/fips.h>
#include <linux/iov_iter.h>
-#include "../common/arc4.h"
#include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
+#include <crypto/arc4.h>
+#include <crypto/md5.h>
+#include <crypto/sha2.h>
-static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
- void *priv, void *priv2)
+static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
+ void *priv, void *priv2)
{
- struct shash_desc *shash = priv;
- int ret, *pret = priv2;
+ struct cifs_calc_sig_ctx *ctx = priv;
- ret = crypto_shash_update(shash, iter_base, len);
- if (ret < 0) {
- *pret = ret;
- return len;
- }
- return 0;
+ if (ctx->md5)
+ md5_update(ctx->md5, iter_base, len);
+ else if (ctx->hmac)
+ hmac_sha256_update(ctx->hmac, iter_base, len);
+ else
+ aes_cmac_update(ctx->cmac, iter_base, len);
+ return 0; /* Return value is length *not* processed, i.e. 0. */
+}
+
+static void cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
+{
+ if (ctx->md5)
+ md5_final(ctx->md5, out);
+ else if (ctx->hmac)
+ hmac_sha256_final(ctx->hmac, out);
+ else
+ aes_cmac_final(ctx->cmac, out);
}
/*
* Pass the data from an iterator into a hash.
*/
-static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize,
- struct shash_desc *shash)
+static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
+ struct cifs_calc_sig_ctx *ctx)
{
struct iov_iter tmp_iter = *iter;
- int err = -EIO;
+ size_t did;
- if (iterate_and_advance_kernel(&tmp_iter, maxsize, shash, &err,
- cifs_shash_step) != maxsize)
- return err;
+ did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, NULL,
+ cifs_sig_step);
+ if (did != maxsize)
+ return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
return 0;
}
-int __cifs_calc_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server, char *signature,
- struct shash_desc *shash)
+int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+ char *signature, struct cifs_calc_sig_ctx *ctx)
{
- int i;
+ struct iov_iter iter;
ssize_t rc;
- struct kvec *iov = rqst->rq_iov;
- int n_vec = rqst->rq_nvec;
-
- /* iov[0] is actual data and not the rfc1002 length for SMB2+ */
- if (!is_smb1(server)) {
- if (iov[0].iov_len <= 4)
- return -EIO;
- i = 0;
- } else {
- if (n_vec < 2 || iov[0].iov_len != 4)
- return -EIO;
- i = 1; /* skip rfc1002 length */
- }
-
- for (; i < n_vec; i++) {
- if (iov[i].iov_len == 0)
- continue;
- if (iov[i].iov_base == NULL) {
- cifs_dbg(VFS, "null iovec entry\n");
- return -EIO;
- }
-
- rc = crypto_shash_update(shash,
- iov[i].iov_base, iov[i].iov_len);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with payload\n",
- __func__);
- return rc;
- }
- }
-
- rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash);
- if (rc < 0)
- return rc;
-
- rc = crypto_shash_final(shash, signature);
- if (rc)
- cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
-
- return rc;
-}
-
-/*
- * Calculate and return the CIFS signature based on the mac key and SMB PDU.
- * The 16 byte signature must be allocated by the caller. Note we only use the
- * 1st eight bytes and that the smb header signature field on input contains
- * the sequence number before this function is called. Also, this function
- * should be called with the server->srv_mutex held.
- */
-static int cifs_calc_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server, char *signature)
-{
- int rc;
-
- if (!rqst->rq_iov || !signature || !server)
- return -EINVAL;
-
- rc = cifs_alloc_hash("md5", &server->secmech.md5);
- if (rc)
- return -1;
-
- rc = crypto_shash_init(server->secmech.md5);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
- return rc;
- }
-
- rc = crypto_shash_update(server->secmech.md5,
- server->session_key.response, server->session_key.len);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
- return rc;
- }
+ size_t size = 0;
- return __cifs_calc_signature(rqst, server, signature, server->secmech.md5);
-}
-
-/* must be called with server->srv_mutex held */
-int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
- __u32 *pexpected_response_sequence_number)
-{
- int rc = 0;
- char smb_signature[20];
- struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+ for (int i = 0; i < rqst->rq_nvec; i++)
+ size += rqst->rq_iov[i].iov_len;
- if (rqst->rq_iov[0].iov_len != 4 ||
- rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
- return -EIO;
-
- if ((cifs_pdu == NULL) || (server == NULL))
- return -EINVAL;
+ iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, size);
- spin_lock(&server->srv_lock);
- if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
- server->tcpStatus == CifsNeedNegotiate) {
- spin_unlock(&server->srv_lock);
- return rc;
- }
- spin_unlock(&server->srv_lock);
+ if (iov_iter_count(&iter) <= 4)
+ return smb_EIO2(smb_eio_trace_sig_data_too_small,
+ iov_iter_count(&iter), 4);
- if (!server->session_estab) {
- memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+ rc = cifs_sig_iter(&iter, iov_iter_count(&iter), ctx);
+ if (rc < 0)
return rc;
- }
-
- cifs_pdu->Signature.Sequence.SequenceNumber =
- cpu_to_le32(server->sequence_number);
- cifs_pdu->Signature.Sequence.Reserved = 0;
-
- *pexpected_response_sequence_number = ++server->sequence_number;
- ++server->sequence_number;
-
- rc = cifs_calc_signature(rqst, server, smb_signature);
- if (rc)
- memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
- else
- memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
-
- return rc;
-}
-
-int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
- __u32 *pexpected_response_sequence)
-{
- struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = n_vec };
-
- return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
-}
-
-/* must be called with server->srv_mutex held */
-int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
- __u32 *pexpected_response_sequence_number)
-{
- struct kvec iov[2];
-
- iov[0].iov_base = cifs_pdu;
- iov[0].iov_len = 4;
- iov[1].iov_base = (char *)cifs_pdu + 4;
- iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
-
- return cifs_sign_smbv(iov, 2, server,
- pexpected_response_sequence_number);
-}
-
-int cifs_verify_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server,
- __u32 expected_sequence_number)
-{
- unsigned int rc;
- char server_response_sig[8];
- char what_we_think_sig_should_be[20];
- struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
-
- if (rqst->rq_iov[0].iov_len != 4 ||
- rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
- return -EIO;
-
- if (cifs_pdu == NULL || server == NULL)
- return -EINVAL;
-
- if (!server->session_estab)
- return 0;
-
- if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
- struct smb_com_lock_req *pSMB =
- (struct smb_com_lock_req *)cifs_pdu;
- if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
- return 0;
- }
-
- /* BB what if signatures are supposed to be on for session but
- server does not send one? BB */
-
- /* Do not need to verify session setups with signature "BSRSPYL " */
- if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
- cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
- cifs_pdu->Command);
-
- /* save off the original signature so we can modify the smb and check
- its signature against what the server sent */
- memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
-
- cifs_pdu->Signature.Sequence.SequenceNumber =
- cpu_to_le32(expected_sequence_number);
- cifs_pdu->Signature.Sequence.Reserved = 0;
-
- cifs_server_lock(server);
- rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
- cifs_server_unlock(server);
- if (rc)
+ rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx);
+ if (rc < 0)
return rc;
-/* cifs_dump_mem("what we think it should be: ",
- what_we_think_sig_should_be, 16); */
-
- if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
- return -EACCES;
- else
- return 0;
-
+ cifs_sig_final(ctx, signature);
+ return 0;
}
/* Build a proper attribute value/target info pairs blob.
@@ -343,7 +174,7 @@ static struct ntlmssp2_name *find_next_av(struct cifs_ses *ses,
len = AV_LEN(av);
if (AV_TYPE(av) == NTLMSSP_AV_EOL)
return NULL;
- if (!len || (u8 *)av + sizeof(*av) + len > end)
+ if ((u8 *)av + sizeof(*av) + len > end)
return NULL;
return av;
}
@@ -363,7 +194,7 @@ static int find_av_name(struct cifs_ses *ses, u16 type, char **name, u16 maxlen)
av_for_each_entry(ses, av) {
len = AV_LEN(av);
- if (AV_TYPE(av) != type)
+ if (AV_TYPE(av) != type || !len)
continue;
if (!IS_ALIGNED(len, sizeof(__le16))) {
cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n",
@@ -405,11 +236,11 @@ static __le64 find_timestamp(struct cifs_ses *ses)
}
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
- const struct nls_table *nls_cp, struct shash_desc *hmacmd5)
+ const struct nls_table *nls_cp)
{
- int rc = 0;
int len;
char nt_hash[CIFS_NTHASH_SIZE];
+ struct hmac_md5_ctx hmac_ctx;
__le16 *user;
wchar_t *domain;
wchar_t *server;
@@ -417,17 +248,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
/* calculate md4 hash of password */
E_md4hash(ses->password, nt_hash, nls_cp);
- rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not set NT hash as a key, rc=%d\n", __func__, rc);
- return rc;
- }
-
- rc = crypto_shash_init(hmacmd5);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
- return rc;
- }
+ hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE);
/* convert ses->user_name to unicode */
len = ses->user_name ? strlen(ses->user_name) : 0;
@@ -442,12 +263,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
*(u16 *)user = 0;
}
- rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len);
+ hmac_md5_update(&hmac_ctx, (const u8 *)user, 2 * len);
kfree(user);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with user, rc=%d\n", __func__, rc);
- return rc;
- }
/* convert ses->domainName to unicode and uppercase */
if (ses->domainName) {
@@ -459,12 +276,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
nls_cp);
- rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len);
+ hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len);
kfree(domain);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with domain, rc=%d\n", __func__, rc);
- return rc;
- }
} else {
/* We use ses->ip_addr if no domain name available */
len = strlen(ses->ip_addr);
@@ -474,25 +287,16 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
return -ENOMEM;
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp);
- rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len);
+ hmac_md5_update(&hmac_ctx, (const u8 *)server, 2 * len);
kfree(server);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with server, rc=%d\n", __func__, rc);
- return rc;
- }
}
- rc = crypto_shash_final(hmacmd5, ntlmv2_hash);
- if (rc)
- cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
-
- return rc;
+ hmac_md5_final(&hmac_ctx, ntlmv2_hash);
+ return 0;
}
-static int
-CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_desc *hmacmd5)
+static void CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
{
- int rc;
struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
unsigned int hash_len;
@@ -501,48 +305,77 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_
hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
offsetof(struct ntlmv2_resp, challenge.key[0]));
- rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
- return rc;
- }
-
- rc = crypto_shash_init(hmacmd5);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
- return rc;
- }
-
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
memcpy(ntlmv2->challenge.key, ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
else
memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
- rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc);
- return rc;
+ /* Note that the HMAC-MD5 value overwrites ntlmv2->challenge.key */
+ hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
+ ntlmv2->challenge.key, hash_len,
+ ntlmv2->ntlmv2_hash);
+}
+
+/*
+ * Set up NTLMv2 response blob with SPN (cifs/<hostname>) appended to the
+ * existing list of AV pairs.
+ */
+static int set_auth_key_response(struct cifs_ses *ses)
+{
+ size_t baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
+ size_t len, spnlen, tilen = 0, num_avs = 2 /* SPN + EOL */;
+ struct TCP_Server_Info *server = ses->server;
+ char *spn __free(kfree) = NULL;
+ struct ntlmssp2_name *av;
+ char *rsp = NULL;
+ int rc;
+
+ spnlen = strlen(server->hostname);
+ len = sizeof("cifs/") + spnlen;
+ spn = kmalloc(len, GFP_KERNEL);
+ if (!spn) {
+ rc = -ENOMEM;
+ goto out;
}
- /* Note that the MD5 digest over writes anon.challenge_key.key */
- rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash);
- if (rc)
- cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
+ spnlen = scnprintf(spn, len, "cifs/%.*s",
+ (int)spnlen, server->hostname);
+ av_for_each_entry(ses, av)
+ tilen += sizeof(*av) + AV_LEN(av);
+
+ len = baselen + tilen + spnlen * sizeof(__le16) + num_avs * sizeof(*av);
+ rsp = kmalloc(len, GFP_KERNEL);
+ if (!rsp) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(rsp + baselen, ses->auth_key.response, tilen);
+ av = (void *)(rsp + baselen + tilen);
+ av->type = cpu_to_le16(NTLMSSP_AV_TARGET_NAME);
+ av->length = cpu_to_le16(spnlen * sizeof(__le16));
+ cifs_strtoUTF16((__le16 *)av->data, spn, spnlen, ses->local_nls);
+ av = (void *)((__u8 *)av + sizeof(*av) + AV_LEN(av));
+ av->type = cpu_to_le16(NTLMSSP_AV_EOL);
+ av->length = 0;
+
+ rc = 0;
+ ses->auth_key.len = len;
+out:
+ ses->auth_key.response = rsp;
return rc;
}
int
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
{
- struct shash_desc *hmacmd5 = NULL;
- int rc;
- int baselen;
- unsigned int tilen;
+ unsigned char *tiblob = NULL; /* target info blob */
struct ntlmv2_resp *ntlmv2;
char ntlmv2_hash[16];
- unsigned char *tiblob = NULL; /* target info blob */
__le64 rsp_timestamp;
+ __u64 cc;
+ int rc;
if (nls_cp == NULL) {
cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__);
@@ -588,77 +421,48 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
* (as Windows 7 does)
*/
rsp_timestamp = find_timestamp(ses);
+ get_random_bytes(&cc, sizeof(cc));
- baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
- tilen = ses->auth_key.len;
- tiblob = ses->auth_key.response;
+ cifs_server_lock(ses->server);
- ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
- if (!ses->auth_key.response) {
- rc = -ENOMEM;
+ tiblob = ses->auth_key.response;
+ rc = set_auth_key_response(ses);
+ if (rc) {
ses->auth_key.len = 0;
- goto setup_ntlmv2_rsp_ret;
+ goto unlock;
}
- ses->auth_key.len += baselen;
ntlmv2 = (struct ntlmv2_resp *)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0;
ntlmv2->time = rsp_timestamp;
-
- get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
+ ntlmv2->client_chal = cc;
ntlmv2->reserved2 = 0;
- memcpy(ses->auth_key.response + baselen, tiblob, tilen);
-
- cifs_server_lock(ses->server);
-
- rc = cifs_alloc_hash("hmac(md5)", &hmacmd5);
- if (rc) {
- cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc);
+ if (fips_enabled) {
+ cifs_dbg(VFS, "NTLMv2 support is disabled due to FIPS\n");
+ rc = -EOPNOTSUPP;
goto unlock;
}
/* calculate ntlmv2_hash */
- rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5);
+ rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
if (rc) {
cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc);
goto unlock;
}
/* calculate first part of the client response (CR1) */
- rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5);
- if (rc) {
- cifs_dbg(VFS, "Could not calculate CR1, rc=%d\n", rc);
- goto unlock;
- }
+ CalcNTLMv2_response(ses, ntlmv2_hash);
/* now calculate the session key for NTLMv2 */
- rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
- goto unlock;
- }
-
- rc = crypto_shash_init(hmacmd5);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
- goto unlock;
- }
-
- rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc);
- goto unlock;
- }
-
- rc = crypto_shash_final(hmacmd5, ses->auth_key.response);
- if (rc)
- cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
+ hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
+ ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
+ ses->auth_key.response);
+ rc = 0;
unlock:
cifs_server_unlock(ses->server);
- cifs_free_hash(&hmacmd5);
setup_ntlmv2_rsp_ret:
kfree_sensitive(tiblob);
@@ -676,15 +480,15 @@ calc_seckey(struct cifs_ses *ses)
get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
- ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
+ ctx_arc4 = kmalloc_obj(*ctx_arc4);
if (!ctx_arc4) {
cifs_dbg(VFS, "Could not allocate arc4 context\n");
return -ENOMEM;
}
- cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
- cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
- CIFS_CPHTXT_SIZE);
+ arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
+ arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
+ CIFS_CPHTXT_SIZE);
/* make secondary_key/nonce as session key */
memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
@@ -699,11 +503,6 @@ calc_seckey(struct cifs_ses *ses)
void
cifs_crypto_secmech_release(struct TCP_Server_Info *server)
{
- cifs_free_hash(&server->secmech.aes_cmac);
- cifs_free_hash(&server->secmech.hmacsha256);
- cifs_free_hash(&server->secmech.md5);
- cifs_free_hash(&server->secmech.sha512);
-
if (server->secmech.enc) {
crypto_free_aead(server->secmech.enc);
server->secmech.enc = NULL;
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index a08c42363ffc..9f76b0347fa9 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -28,17 +28,17 @@
#include <linux/splice.h>
#include <linux/uuid.h>
#include <linux/xattr.h>
+#include <linux/mm.h>
+#include <linux/key-type.h>
#include <uapi/linux/magic.h>
#include <net/ipv6.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#define DECLARE_GLOBALS_HERE
#include "cifsglob.h"
#include "cifsproto.h"
+#include "smb2proto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
-#include <linux/mm.h>
-#include <linux/key-type.h>
#include "cifs_spnego.h"
#include "fscache.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -70,7 +70,6 @@ bool require_gcm_256; /* false by default */
bool enable_negotiate_signing; /* false by default */
unsigned int global_secflags = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
-unsigned int sign_CIFS_PDUs = 1;
/*
* Global transaction id (XID) information
@@ -78,7 +77,7 @@ unsigned int sign_CIFS_PDUs = 1;
unsigned int GlobalCurrentXid; /* protected by GlobalMid_Lock */
unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Lock */
unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Lock */
-spinlock_t GlobalMid_Lock; /* protects above & list operations on midQ entries */
+DEFINE_SPINLOCK(GlobalMid_Lock); /* protects above & list operations on midQ entries */
/*
* Global counters, updated atomically
@@ -98,7 +97,7 @@ atomic_t total_buf_alloc_count;
atomic_t total_small_buf_alloc_count;
#endif/* STATS2 */
struct list_head cifs_tcp_ses_list;
-spinlock_t cifs_tcp_ses_lock;
+DEFINE_SPINLOCK(cifs_tcp_ses_lock);
static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, uint, 0444);
@@ -122,6 +121,12 @@ unsigned int dir_cache_timeout = 30;
module_param(dir_cache_timeout, uint, 0644);
MODULE_PARM_DESC(dir_cache_timeout, "Number of seconds to cache directory contents for which we have a lease. Default: 30 "
"Range: 1 to 65000 seconds, 0 to disable caching dir contents");
+/* Module-wide total cached dirents (in bytes) across all tcons */
+atomic64_t cifs_dircache_bytes_used = ATOMIC64_INIT(0);
+
+atomic_t cifs_sillycounter;
+atomic_t cifs_tmpcounter;
+
#ifdef CONFIG_CIFS_STATS2
unsigned int slow_rsp_threshold = 1;
module_param(slow_rsp_threshold, uint, 0644);
@@ -134,7 +139,7 @@ module_param(enable_oplocks, bool, 0644);
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1");
module_param(enable_gcm_256, bool, 0644);
-MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/0");
+MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/1");
module_param(require_gcm_256, bool, 0644);
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");
@@ -187,16 +192,18 @@ cifs_sb_deactive(struct super_block *sb)
static int
cifs_read_super(struct super_block *sb)
{
- struct inode *inode;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
+ unsigned int sbflags;
struct timespec64 ts;
+ struct inode *inode;
int rc = 0;
cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
+ sbflags = cifs_sb_flags(cifs_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
+ if (sbflags & CIFS_MOUNT_POSIXACL)
sb->s_flags |= SB_POSIXACL;
if (tcon->snapshot_time)
@@ -261,9 +268,9 @@ cifs_read_super(struct super_block *sb)
}
if (tcon->nocase)
- sb->s_d_op = &cifs_ci_dentry_ops;
+ set_default_d_op(sb, &cifs_ci_dentry_ops);
else
- sb->s_d_op = &cifs_dentry_ops;
+ set_default_d_op(sb, &cifs_dentry_ops);
sb->s_root = d_make_root(inode);
if (!sb->s_root) {
@@ -272,7 +279,7 @@ cifs_read_super(struct super_block *sb)
}
#ifdef CONFIG_CIFS_NFSD_EXPORT
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ if (sbflags & CIFS_MOUNT_SERVER_INUM) {
cifs_dbg(FYI, "export ops supported\n");
sb->s_export_op = &cifs_export_ops;
}
@@ -291,10 +298,14 @@ static void cifs_kill_sb(struct super_block *sb)
/*
* We need to release all dentries for the cached directories
- * before we kill the sb.
+ * and close all deferred file handles before we kill the sb.
*/
if (cifs_sb->root) {
close_all_cached_dirs(cifs_sb);
+ cifs_close_all_deferred_files_sb(cifs_sb);
+
+ /* Wait for all pending oplock breaks to complete */
+ flush_workqueue(cifsoplockd_wq);
/* finally release root dentry */
dput(cifs_sb->root);
@@ -350,24 +361,37 @@ statfs_out:
static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
{
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
- struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(CIFS_SB(file));
struct TCP_Server_Info *server = tcon->ses->server;
+ struct inode *inode = file_inode(file);
+ int rc;
+
+ if (!server->ops->fallocate)
+ return -EOPNOTSUPP;
+
+ rc = inode_lock_killable(inode);
+ if (rc)
+ return rc;
+
+ netfs_wait_for_outstanding_io(inode);
+
+ rc = file_modified(file);
+ if (rc)
+ goto out_unlock;
- if (server->ops->fallocate)
- return server->ops->fallocate(file, tcon, mode, off, len);
+ rc = server->ops->fallocate(file, tcon, mode, off, len);
- return -EOPNOTSUPP;
+out_unlock:
+ inode_unlock(inode);
+ return rc;
}
static int cifs_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask)
{
- struct cifs_sb_info *cifs_sb;
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
- cifs_sb = CIFS_SB(inode->i_sb);
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
+ if (sbflags & CIFS_MOUNT_NO_PERM) {
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
else
@@ -387,7 +411,7 @@ static struct kmem_cache *cifs_io_request_cachep;
static struct kmem_cache *cifs_io_subrequest_cachep;
mempool_t *cifs_sm_req_poolp;
mempool_t *cifs_req_poolp;
-mempool_t *cifs_mid_poolp;
+mempool_t cifs_mid_pool;
mempool_t cifs_io_request_pool;
mempool_t cifs_io_subrequest_pool;
@@ -445,7 +469,7 @@ cifs_evict_inode(struct inode *inode)
{
netfs_wait_for_outstanding_io(inode);
truncate_inode_pages_final(&inode->i_data);
- if (inode->i_state & I_PINNING_NETFS_WB)
+ if (inode_state_read_once(inode) & I_PINNING_NETFS_WB)
cifs_fscache_unuse_inode_cookie(inode, true);
cifs_fscache_release_inode_cookie(inode);
clear_inode(inode);
@@ -513,15 +537,17 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
static void
cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
seq_puts(s, ",cache=");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+ if (sbflags & CIFS_MOUNT_STRICT_IO)
seq_puts(s, "strict");
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+ else if (sbflags & CIFS_MOUNT_DIRECT_IO)
seq_puts(s, "none");
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
+ else if (sbflags & CIFS_MOUNT_RW_CACHE)
seq_puts(s, "singleclient"); /* assume only one client access */
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)
+ else if (sbflags & CIFS_MOUNT_RO_CACHE)
seq_puts(s, "ro"); /* read only caching assumed */
else
seq_puts(s, "loose");
@@ -582,6 +608,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct sockaddr *srcaddr;
+ unsigned int sbflags;
+
srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
@@ -615,16 +643,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
(int)(srcaddr->sa_family));
}
+ sbflags = cifs_sb_flags(cifs_sb);
seq_printf(s, ",uid=%u",
from_kuid_munged(&init_user_ns, cifs_sb->ctx->linux_uid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ if (sbflags & CIFS_MOUNT_OVERR_UID)
seq_puts(s, ",forceuid");
else
seq_puts(s, ",noforceuid");
seq_printf(s, ",gid=%u",
from_kgid_munged(&init_user_ns, cifs_sb->ctx->linux_gid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ if (sbflags & CIFS_MOUNT_OVERR_GID)
seq_puts(s, ",forcegid");
else
seq_puts(s, ",noforcegid");
@@ -667,53 +696,53 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",unix");
else
seq_puts(s, ",nounix");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
+ if (sbflags & CIFS_MOUNT_NO_DFS)
seq_puts(s, ",nodfs");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ if (sbflags & CIFS_MOUNT_POSIX_PATHS)
seq_puts(s, ",posixpaths");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
+ if (sbflags & CIFS_MOUNT_SET_UID)
seq_puts(s, ",setuids");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
+ if (sbflags & CIFS_MOUNT_UID_FROM_ACL)
seq_puts(s, ",idsfromsid");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+ if (sbflags & CIFS_MOUNT_SERVER_INUM)
seq_puts(s, ",serverino");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+ if (sbflags & CIFS_MOUNT_RWPIDFORWARD)
seq_puts(s, ",rwpidforward");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL)
+ if (sbflags & CIFS_MOUNT_NOPOSIXBRL)
seq_puts(s, ",forcemand");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (sbflags & CIFS_MOUNT_NO_XATTR)
seq_puts(s, ",nouser_xattr");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ if (sbflags & CIFS_MOUNT_MAP_SPECIAL_CHR)
seq_puts(s, ",mapchars");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
+ if (sbflags & CIFS_MOUNT_MAP_SFM_CHR)
seq_puts(s, ",mapposix");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ if (sbflags & CIFS_MOUNT_UNX_EMUL)
seq_puts(s, ",sfu");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (sbflags & CIFS_MOUNT_NO_BRL)
seq_puts(s, ",nobrl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_HANDLE_CACHE)
+ if (sbflags & CIFS_MOUNT_NO_HANDLE_CACHE)
seq_puts(s, ",nohandlecache");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
+ if (sbflags & CIFS_MOUNT_MODE_FROM_SID)
seq_puts(s, ",modefromsid");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+ if (sbflags & CIFS_MOUNT_CIFS_ACL)
seq_puts(s, ",cifsacl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
seq_puts(s, ",dynperm");
if (root->d_sb->s_flags & SB_POSIXACL)
seq_puts(s, ",acl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS)
seq_puts(s, ",mfsymlinks");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
+ if (sbflags & CIFS_MOUNT_FSCACHE)
seq_puts(s, ",fsc");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
+ if (sbflags & CIFS_MOUNT_NOSSYNC)
seq_puts(s, ",nostrictsync");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (sbflags & CIFS_MOUNT_NO_PERM)
seq_puts(s, ",noperm");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID)
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPUID)
seq_printf(s, ",backupuid=%u",
from_kuid_munged(&init_user_ns,
cifs_sb->ctx->backupuid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID)
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPGID)
seq_printf(s, ",backupgid=%u",
from_kgid_munged(&init_user_ns,
cifs_sb->ctx->backupgid));
@@ -724,7 +753,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
else
seq_puts(s, ",nativesocket");
seq_show_option(s, "symlink",
- cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb)));
+ cifs_symlink_type_str(cifs_symlink_type(cifs_sb)));
seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize);
seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize);
@@ -809,7 +838,6 @@ static void cifs_umount_begin(struct super_block *sb)
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
- cifs_close_all_deferred_files(tcon);
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
if (tcon->ses && tcon->ses->server) {
@@ -854,11 +882,11 @@ static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc)
static int cifs_drop_inode(struct inode *inode)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
/* no serverino => unconditional eviction */
- return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) ||
- generic_drop_inode(inode);
+ return !(sbflags & CIFS_MOUNT_SERVER_INUM) ||
+ inode_generic_drop(inode);
}
static const struct super_operations cifs_super_ops = {
@@ -895,7 +923,7 @@ cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb)
char *s, *p;
char sep;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH)
return dget(sb->s_root);
full_path = cifs_build_path_to_root(ctx, cifs_sb,
@@ -929,7 +957,8 @@ cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb)
while (*s && *s != sep)
s++;
- child = lookup_positive_unlocked(p, dentry, s - p);
+ child = lookup_noperm_positive_unlocked(&QSTR_LEN(p, s - p),
+ dentry);
dput(dentry);
dentry = child;
} while (!IS_ERR(dentry));
@@ -960,12 +989,11 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
} else {
cifs_info("Attempting to mount %s\n", old_ctx->source);
}
-
- cifs_sb = kzalloc(sizeof(*cifs_sb), GFP_KERNEL);
+ cifs_sb = kzalloc_obj(*cifs_sb);
if (!cifs_sb)
return ERR_PTR(-ENOMEM);
- cifs_sb->ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
+ cifs_sb->ctx = kzalloc_obj(struct smb3_fs_context);
if (!cifs_sb->ctx) {
root = ERR_PTR(-ENOMEM);
goto out;
@@ -1137,6 +1165,7 @@ MODULE_ALIAS("smb3");
const struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create,
.atomic_open = cifs_atomic_open,
+ .tmpfile = cifs_tmpfile,
.lookup = cifs_lookup,
.getattr = cifs_getattr,
.unlink = cifs_unlink,
@@ -1207,7 +1236,7 @@ static int cifs_precopy_set_eof(struct inode *src_inode, struct cifsInodeInfo *s
struct cifsFileInfo *writeable_srcfile;
int rc = -EINVAL;
- writeable_srcfile = find_writable_file(src_cifsi, FIND_WR_FSUID_ONLY);
+ writeable_srcfile = find_writable_file(src_cifsi, FIND_FSUID_ONLY);
if (writeable_srcfile) {
if (src_tcon->ses->server->ops->set_file_size)
rc = src_tcon->ses->server->ops->set_file_size(
@@ -1358,6 +1387,20 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
truncate_setsize(target_inode, new_size);
fscache_resize_cookie(cifs_inode_cookie(target_inode),
new_size);
+ } else if (rc == -EOPNOTSUPP) {
+ /*
+ * copy_file_range syscall man page indicates EINVAL
+ * is returned e.g when "fd_in and fd_out refer to the
+ * same file and the source and target ranges overlap."
+ * Test generic/157 was what showed these cases where
+ * we need to remap EOPNOTSUPP to EINVAL
+ */
+ if (off >= src_inode->i_size) {
+ rc = -EINVAL;
+ } else if (src_inode == target_inode) {
+ if (off + len > destoff)
+ rc = -EINVAL;
+ }
}
if (rc == 0 && new_size > target_cifsi->netfs.zero_point)
target_cifsi->netfs.zero_point = new_size;
@@ -1525,7 +1568,7 @@ const struct file_operations cifs_file_ops = {
.flock = cifs_flock,
.fsync = cifs_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_mmap,
+ .mmap_prepare = cifs_file_mmap_prepare,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
@@ -1545,7 +1588,7 @@ const struct file_operations cifs_file_strict_ops = {
.flock = cifs_flock,
.fsync = cifs_strict_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_strict_mmap,
+ .mmap_prepare = cifs_file_strict_mmap_prepare,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
@@ -1565,7 +1608,7 @@ const struct file_operations cifs_file_direct_ops = {
.flock = cifs_flock,
.fsync = cifs_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_mmap,
+ .mmap_prepare = cifs_file_mmap_prepare,
.splice_read = copy_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = cifs_ioctl,
@@ -1583,7 +1626,7 @@ const struct file_operations cifs_file_nobrl_ops = {
.release = cifs_close,
.fsync = cifs_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_mmap,
+ .mmap_prepare = cifs_file_mmap_prepare,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
@@ -1601,7 +1644,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
.release = cifs_close,
.fsync = cifs_strict_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_strict_mmap,
+ .mmap_prepare = cifs_file_strict_mmap_prepare,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
@@ -1619,7 +1662,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.release = cifs_close,
.fsync = cifs_fsync,
.flush = cifs_flush,
- .mmap = cifs_file_mmap,
+ .mmap_prepare = cifs_file_mmap_prepare,
.splice_read = copy_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = cifs_ioctl,
@@ -1774,8 +1817,7 @@ static int init_mids(void)
return -ENOMEM;
/* 3 is a reasonable minimum number of simultaneous operations */
- cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
- if (cifs_mid_poolp == NULL) {
+ if (mempool_init_slab_pool(&cifs_mid_pool, 3, cifs_mid_cachep) < 0) {
kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM;
}
@@ -1785,7 +1827,7 @@ static int init_mids(void)
static void destroy_mids(void)
{
- mempool_destroy(cifs_mid_poolp);
+ mempool_exit(&cifs_mid_pool);
kmem_cache_destroy(cifs_mid_cachep);
}
@@ -1835,6 +1877,17 @@ static int __init
init_cifs(void)
{
int rc = 0;
+
+#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
+ rc = smb1_init_maperror();
+ if (rc)
+ return rc;
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+
+ rc = smb2_init_maperror();
+ if (rc)
+ return rc;
+
cifs_proc_init();
INIT_LIST_HEAD(&cifs_tcp_ses_list);
/*
@@ -1863,8 +1916,6 @@ init_cifs(void)
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
- spin_lock_init(&cifs_tcp_ses_lock);
- spin_lock_init(&GlobalMid_Lock);
cifs_lock_secret = get_random_u32();
@@ -1883,7 +1934,9 @@ init_cifs(void)
cifs_dbg(VFS, "dir_cache_timeout set to max of 65000 seconds\n");
}
- cifsiod_wq = alloc_workqueue("cifsiod", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ cifsiod_wq = alloc_workqueue("cifsiod",
+ WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+ 0);
if (!cifsiod_wq) {
rc = -ENOMEM;
goto out_clean_proc;
@@ -1911,28 +1964,32 @@ init_cifs(void)
}
cifsoplockd_wq = alloc_workqueue("cifsoplockd",
- WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+ 0);
if (!cifsoplockd_wq) {
rc = -ENOMEM;
goto out_destroy_fileinfo_put_wq;
}
deferredclose_wq = alloc_workqueue("deferredclose",
- WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+ 0);
if (!deferredclose_wq) {
rc = -ENOMEM;
goto out_destroy_cifsoplockd_wq;
}
serverclose_wq = alloc_workqueue("serverclose",
- WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+ 0);
if (!serverclose_wq) {
rc = -ENOMEM;
goto out_destroy_deferredclose_wq;
}
cfid_put_wq = alloc_workqueue("cfid_put_wq",
- WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+ 0);
if (!cfid_put_wq) {
rc = -ENOMEM;
goto out_destroy_serverclose_wq;
@@ -2064,14 +2121,8 @@ MODULE_DESCRIPTION
("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and "
"also older servers complying with the SNIA CIFS Specification)");
MODULE_VERSION(CIFS_VERSION);
-MODULE_SOFTDEP("ecb");
-MODULE_SOFTDEP("hmac");
-MODULE_SOFTDEP("md5");
MODULE_SOFTDEP("nls");
MODULE_SOFTDEP("aes");
-MODULE_SOFTDEP("cmac");
-MODULE_SOFTDEP("sha256");
-MODULE_SOFTDEP("sha512");
MODULE_SOFTDEP("aead2");
MODULE_SOFTDEP("ccm");
MODULE_SOFTDEP("gcm");
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index ca435a3841b8..c455b15f2778 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -10,9 +10,13 @@
#define _CIFSFS_H
#include <linux/hash.h>
+#include <linux/dcache.h>
#define ROOT_I 2
+extern atomic_t cifs_sillycounter;
+extern atomic_t cifs_tmpcounter;
+
/*
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
* so that it will fit. We use hash_64 to convert the value to 31 bits, and
@@ -43,40 +47,43 @@ extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
-extern void cifs_sb_active(struct super_block *sb);
-extern void cifs_sb_deactive(struct super_block *sb);
+void cifs_sb_active(struct super_block *sb);
+void cifs_sb_deactive(struct super_block *sb);
/* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops;
-extern struct inode *cifs_root_iget(struct super_block *);
-extern int cifs_create(struct mnt_idmap *, struct inode *,
- struct dentry *, umode_t, bool excl);
-extern int cifs_atomic_open(struct inode *, struct dentry *,
- struct file *, unsigned, umode_t);
-extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
- unsigned int);
-extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
-extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
-extern int cifs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
- umode_t, dev_t);
-extern struct dentry *cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *,
- umode_t);
-extern int cifs_rmdir(struct inode *, struct dentry *);
-extern int cifs_rename2(struct mnt_idmap *, struct inode *,
- struct dentry *, struct inode *, struct dentry *,
- unsigned int);
-extern int cifs_revalidate_file_attr(struct file *filp);
-extern int cifs_revalidate_dentry_attr(struct dentry *);
-extern int cifs_revalidate_file(struct file *filp);
-extern int cifs_revalidate_dentry(struct dentry *);
-extern int cifs_revalidate_mapping(struct inode *inode);
-extern int cifs_zap_mapping(struct inode *inode);
-extern int cifs_getattr(struct mnt_idmap *, const struct path *,
- struct kstat *, u32, unsigned int);
-extern int cifs_setattr(struct mnt_idmap *, struct dentry *,
- struct iattr *);
-extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
- u64 len);
+struct inode *cifs_root_iget(struct super_block *sb);
+int cifs_create(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *direntry, umode_t mode, bool excl);
+int cifs_atomic_open(struct inode *dir, struct dentry *direntry,
+ struct file *file, unsigned int oflags, umode_t mode);
+int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
+ struct file *file, umode_t mode);
+struct dentry *cifs_lookup(struct inode *parent_dir_inode,
+ struct dentry *direntry, unsigned int flags);
+int cifs_unlink(struct inode *dir, struct dentry *dentry);
+int cifs_hardlink(struct dentry *old_file, struct inode *inode,
+ struct dentry *direntry);
+int cifs_mknod(struct mnt_idmap *idmap, struct inode *inode,
+ struct dentry *direntry, umode_t mode, dev_t device_number);
+struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
+ struct dentry *direntry, umode_t mode);
+int cifs_rmdir(struct inode *inode, struct dentry *direntry);
+int cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
+ struct dentry *source_dentry, struct inode *target_dir,
+ struct dentry *target_dentry, unsigned int flags);
+int cifs_revalidate_file_attr(struct file *filp);
+int cifs_revalidate_dentry_attr(struct dentry *dentry);
+int cifs_revalidate_file(struct file *filp);
+int cifs_revalidate_dentry(struct dentry *dentry);
+int cifs_revalidate_mapping(struct inode *inode);
+int cifs_zap_mapping(struct inode *inode);
+int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
+ struct kstat *stat, u32 request_mask, unsigned int flags);
+int cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
+ struct iattr *attrs);
+int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
+ u64 len);
extern const struct inode_operations cifs_file_inode_ops;
extern const struct inode_operations cifs_symlink_inode_ops;
@@ -91,60 +98,69 @@ extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */
extern const struct file_operations cifs_file_direct_nobrl_ops;
extern const struct file_operations cifs_file_strict_nobrl_ops;
-extern int cifs_open(struct inode *inode, struct file *file);
-extern int cifs_close(struct inode *inode, struct file *file);
-extern int cifs_closedir(struct inode *inode, struct file *file);
-extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
-extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
+int cifs_open(struct inode *inode, struct file *file);
+int cifs_close(struct inode *inode, struct file *file);
+int cifs_closedir(struct inode *inode, struct file *file);
+ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
+ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from);
ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter);
-extern int cifs_flock(struct file *pfile, int cmd, struct file_lock *plock);
-extern int cifs_lock(struct file *, int, struct file_lock *);
-extern int cifs_fsync(struct file *, loff_t, loff_t, int);
-extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
-extern int cifs_flush(struct file *, fl_owner_t id);
-extern int cifs_file_mmap(struct file *file, struct vm_area_struct *vma);
-extern int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma);
+int cifs_flock(struct file *file, int cmd, struct file_lock *fl);
+int cifs_lock(struct file *file, int cmd, struct file_lock *flock);
+int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
+int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync);
+int cifs_flush(struct file *file, fl_owner_t id);
+int cifs_file_mmap_prepare(struct vm_area_desc *desc);
+int cifs_file_strict_mmap_prepare(struct vm_area_desc *desc);
extern const struct file_operations cifs_dir_ops;
-extern int cifs_readdir(struct file *file, struct dir_context *ctx);
+int cifs_readdir(struct file *file, struct dir_context *ctx);
/* Functions related to dir entries */
extern const struct dentry_operations cifs_dentry_ops;
extern const struct dentry_operations cifs_ci_dentry_ops;
-extern struct vfsmount *cifs_d_automount(struct path *path);
+struct vfsmount *cifs_d_automount(struct path *path);
/* Functions related to symlinks */
-extern const char *cifs_get_link(struct dentry *, struct inode *,
- struct delayed_call *);
-extern int cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
- struct dentry *direntry, const char *symname);
+const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done);
+int cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
+ struct dentry *direntry, const char *symname);
#ifdef CONFIG_CIFS_XATTR
extern const struct xattr_handler * const cifs_xattr_handlers[];
-extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
+ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size);
#else
# define cifs_xattr_handlers NULL
# define cifs_listxattr NULL
#endif
-extern ssize_t cifs_file_copychunk_range(unsigned int xid,
- struct file *src_file, loff_t off,
- struct file *dst_file, loff_t destoff,
- size_t len, unsigned int flags);
+ssize_t cifs_file_copychunk_range(unsigned int xid, struct file *src_file,
+ loff_t off, struct file *dst_file,
+ loff_t destoff, size_t len,
+ unsigned int flags);
-extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
-extern void cifs_setsize(struct inode *inode, loff_t offset);
+long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg);
+void cifs_setsize(struct inode *inode, loff_t offset);
struct smb3_fs_context;
-extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
- int flags, struct smb3_fs_context *ctx);
+struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, int flags,
+ struct smb3_fs_context *old_ctx);
+
+char *cifs_silly_fullpath(struct dentry *dentry);
+
+#define CIFS_TMPNAME_PREFIX ".__smbfile_tmp"
+#define CIFS_TMPNAME_LEN (DNAME_INLINE_LEN - 1)
+
+#define CIFS_SILLYNAME_PREFIX ".__smbfile_silly"
+#define CIFS_SILLYNAME_LEN (DNAME_INLINE_LEN - 1)
#ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */
-#define SMB3_PRODUCT_BUILD 54
-#define CIFS_VERSION "2.54"
+#define SMB3_PRODUCT_BUILD 60
+#define CIFS_VERSION "2.60"
#endif /* _CIFSFS_H */
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 3b32116b0b49..82e0adc1dabd 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -20,12 +20,15 @@
#include <linux/utsname.h>
#include <linux/sched/mm.h>
#include <linux/netfs.h>
+#include <linux/fcntl.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
-#include <crypto/internal/hash.h>
#include <uapi/linux/cifs/cifs_mount.h>
+#include "../common/smbglob.h"
#include "../common/smb2pdu.h"
+#include "../common/fscc.h"
#include "smb2pdu.h"
+#include "smb1pdu.h"
#include <linux/filelock.h>
#define SMB_PATH_MAX 260
@@ -87,7 +90,7 @@
#define SMB_INTERFACE_POLL_INTERVAL 600
/* maximum number of PDUs in one compound */
-#define MAX_COMPOUND 7
+#define MAX_COMPOUND 10
/*
* Default number of credits to keep available for SMB3.
@@ -101,8 +104,6 @@
*/
#define SMB2_MAX_CREDITS_AVAILABLE 32000
-#include "cifspdu.h"
-
#ifndef XATTR_DOS_ATTRIB
#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
#endif
@@ -219,13 +220,8 @@ struct session_key {
char *response;
};
-/* crypto hashing related structure/fields, not specific to a sec mech */
+/* encryption related structure/fields, not specific to a sec mech */
struct cifs_secmech {
- struct shash_desc *md5; /* md5 hash function, for CIFS/SMB1 signatures */
- struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 signatures */
- struct shash_desc *sha512; /* sha512 hash function, for SMB3.1.1 preauth hash */
- struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */
-
struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */
struct crypto_aead *dec; /* smb3 decryption AEAD TFM (AES-CCM and AES-GCM) */
};
@@ -312,8 +308,9 @@ struct cifs_open_parms;
struct cifs_credits;
struct smb_version_operations {
- int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
- struct mid_q_entry *);
+ int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, struct mid_q_entry *mid,
+ unsigned int xid);
bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
/* setup request: allocate mid, sign message */
struct mid_q_entry *(*setup_request)(struct cifs_ses *,
@@ -347,13 +344,14 @@ struct smb_version_operations {
/* map smb to linux error */
int (*map_error)(char *, bool);
/* find mid corresponding to the response message */
- struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *);
- void (*dump_detail)(void *buf, struct TCP_Server_Info *ptcp_info);
+ struct mid_q_entry *(*find_mid)(struct TCP_Server_Info *server, char *buf);
+ void (*dump_detail)(void *buf, size_t buf_len, struct TCP_Server_Info *ptcp_info);
void (*clear_stats)(struct cifs_tcon *);
void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
/* verify the message */
- int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
+ int (*check_message)(char *buf, unsigned int pdu_len, unsigned int len,
+ struct TCP_Server_Info *server);
bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info *);
void (*downgrade_oplock)(struct TCP_Server_Info *server,
@@ -515,8 +513,10 @@ struct smb_version_operations {
/* check for STATUS_NETWORK_SESSION_EXPIRED */
bool (*is_session_expired)(char *);
/* send oplock break response */
- int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid, __u64 volatile_fid,
- __u16 net_fid, struct cifsInodeInfo *cifs_inode);
+ int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid,
+ __u64 volatile_fid, __u16 net_fid,
+ struct cifsInodeInfo *cifs_inode,
+ unsigned int oplock);
/* query remote filesystem */
int (*queryfs)(const unsigned int, struct cifs_tcon *,
const char *, struct cifs_sb_info *, struct kstatfs *);
@@ -536,8 +536,6 @@ struct smb_version_operations {
void (*new_lease_key)(struct cifs_fid *);
int (*generate_signingkey)(struct cifs_ses *ses,
struct TCP_Server_Info *server);
- int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
- bool allocate_crypto);
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
struct cifsFileInfo *src_file);
int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
@@ -556,7 +554,7 @@ struct smb_version_operations {
void (*set_oplock_level)(struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch,
bool *purge_cache);
/* create lease context buffer for CREATE request */
- char * (*create_lease_buf)(u8 *lease_key, u8 oplock);
+ char * (*create_lease_buf)(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 le_flags);
/* parse lease context buffer and return oplock/epoch info */
__u8 (*parse_lease_buf)(void *buf, __u16 *epoch, char *lkey);
ssize_t (*copychunk_range)(const unsigned int,
@@ -627,40 +625,19 @@ struct smb_version_operations {
bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
struct reparse_data_buffer * (*get_reparse_point_buffer)(const struct kvec *rsp_iov,
u32 *plen);
- int (*create_reparse_symlink)(const unsigned int xid,
- struct inode *inode,
- struct dentry *dentry,
- struct cifs_tcon *tcon,
- const char *full_path,
- const char *symname);
-};
-
-struct smb_version_values {
- char *version_string;
- __u16 protocol_id;
- __u32 req_capabilities;
- __u32 large_lock_type;
- __u32 exclusive_lock_type;
- __u32 shared_lock_type;
- __u32 unlock_lock_type;
- size_t header_preamble_size;
- size_t header_size;
- size_t max_header_size;
- size_t read_rsp_size;
- __le16 lock_cmd;
- unsigned int cap_unix;
- unsigned int cap_nt_find;
- unsigned int cap_large_files;
- unsigned int cap_unicode;
- __u16 signing_enabled;
- __u16 signing_required;
- size_t create_lease_size;
+ struct inode * (*create_reparse_inode)(struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid,
+ struct cifs_tcon *tcon,
+ const char *full_path,
+ bool directory,
+ struct kvec *reparse_iov,
+ struct kvec *xattr_iov);
};
#define HEADER_SIZE(server) (server->vals->header_size)
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
-#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
-#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
+#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1)
/**
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
@@ -694,21 +671,10 @@ struct cifs_mnt_data {
int flags;
};
-static inline unsigned int
-get_rfc1002_length(void *buf)
-{
- return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
-}
-
-static inline void
-inc_rfc1001_len(void *buf, int count)
-{
- be32_add_cpu((__be32 *)buf, count);
-}
-
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
+ struct list_head rlist; /* reconnect list */
spinlock_t srv_lock; /* protect anything here that is not protected */
__u64 conn_id; /* connection identifier (useful for debugging) */
int srv_count; /* reference counter */
@@ -729,14 +695,15 @@ struct TCP_Server_Info {
#endif
wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
- spinlock_t mid_lock; /* protect mid queue and it's entries */
+ spinlock_t mid_queue_lock; /* protect mid queue */
+ spinlock_t mid_counter_lock;
struct list_head pending_mid_q;
bool noblocksnd; /* use blocking sendmsg */
bool noautotune; /* do not autotune send buf sizes */
bool nosharesock;
bool tcp_nodelay;
bool terminate;
- unsigned int credits; /* send no more requests at once */
+ int credits; /* send no more requests at once */
unsigned int max_credits; /* can override large 32000 default at mnt */
unsigned int in_flight; /* number of requests on the wire to server */
unsigned int max_in_flight; /* max number of requests that were on wire */
@@ -767,14 +734,17 @@ struct TCP_Server_Info {
/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
unsigned int capabilities; /* selective disabling of caps by smb sess */
int timeAdj; /* Adjust for difference in server time zone in sec */
- __u64 CurrentMid; /* multiplex id - rotating counter, protected by GlobalMid_Lock */
+ __u64 current_mid; /* multiplex id - rotating counter, protected by mid_counter_lock */
char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
/* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* for signing, protected by srv_mutex */
__u32 reconnect_instance; /* incremented on each reconnect */
+ __le32 session_key_id; /* retrieved from negotiate response and send in session setup request */
struct session_key session_key;
unsigned long lstrp; /* when we got last response from this server */
+ unsigned long neg_start; /* when negotiate started (jiffies) */
+ unsigned long reconn_delay; /* when resched session and tcon reconnect */
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
#define CIFS_NEGFLAVOR_UNENCAP 1 /* wct == 17, but no ext_sec */
#define CIFS_NEGFLAVOR_EXTENDED 2 /* wct == 17, ext_sec bit set */
@@ -808,6 +778,13 @@ struct TCP_Server_Info {
unsigned int max_read;
unsigned int max_write;
unsigned int min_offload;
+ /*
+ * If payload is less than or equal to the threshold,
+ * use RDMA send/recv to send upper layer I/O.
+ * If payload is more than the threshold,
+ * use RDMA read/write through memory registration for I/O.
+ */
+ unsigned int rdma_readwrite_threshold;
unsigned int retrans;
struct {
bool requested; /* "compress" mount option set*/
@@ -856,9 +833,9 @@ struct TCP_Server_Info {
char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1];
};
-static inline bool is_smb1(struct TCP_Server_Info *server)
+static inline bool is_smb1(const struct TCP_Server_Info *server)
{
- return HEADER_PREAMBLE_SIZE(server) != 0;
+ return server->vals->protocol_id == SMB10_PROT_ID;
}
static inline void cifs_server_lock(struct TCP_Server_Info *server)
@@ -972,18 +949,6 @@ revert_current_mid_from_hdr(struct TCP_Server_Info *server,
return revert_current_mid(server, num > 0 ? num : 1);
}
-static inline __u16
-get_mid(const struct smb_hdr *smb)
-{
- return le16_to_cpu(smb->Mid);
-}
-
-static inline bool
-compare_mid(__u16 mid, const struct smb_hdr *smb)
-{
- return mid == le16_to_cpu(smb->Mid);
-}
-
/*
* When the server supports very large reads and writes via POSIX extensions,
* we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
@@ -997,18 +962,16 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)
* of kvecs to handle the receive, though that should only need to be done
* once.
*/
-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ))
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP))
/*
* When the server doesn't allow large posix writes, only allow a rsize/wsize
* of 2^17-1 minus the size of the call header. That allows for a read or
* write up to the maximum size described by RFC1002.
*/
-#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
-
-#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ))
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP))
/*
* Windows only supports a max of 60kb reads and 65535 byte writes. Default to
@@ -1084,6 +1047,7 @@ struct cifs_chan {
};
#define CIFS_SES_FLAG_SCALE_CHANNELS (0x1)
+#define CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES (0x2)
/*
* Session structure. One of these for each uid session with a particular host
@@ -1300,6 +1264,7 @@ struct cifs_tcon {
bool use_persistent:1; /* use persistent instead of durable handles */
bool no_lease:1; /* Do not request leases on files or directories */
bool use_witness:1; /* use witness protocol */
+ bool dummy:1; /* dummy tcon used for reconnecting channels */
__le32 capabilities;
__u32 share_flags;
__u32 maximal_access;
@@ -1349,8 +1314,8 @@ struct tcon_link {
struct cifs_tcon *tl_tcon;
};
-extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
-extern void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst);
+struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
+void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst);
static inline struct cifs_tcon *
tlink_tcon(struct tcon_link *tlink)
@@ -1364,7 +1329,7 @@ cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
return cifs_sb->master_tlink;
}
-extern void cifs_put_tlink(struct tcon_link *tlink);
+void cifs_put_tlink(struct tcon_link *tlink);
static inline struct tcon_link *
cifs_get_tlink(struct tcon_link *tlink)
@@ -1375,7 +1340,7 @@ cifs_get_tlink(struct tcon_link *tlink)
}
/* This function is always expected to succeed */
-extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
+struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
#define CIFS_OPLOCK_NO_CHANGE 0xfe
@@ -1441,6 +1406,7 @@ struct cifs_open_parms {
bool reconnect:1;
bool replay:1; /* indicates that this open is for a replay */
struct kvec *ea_cctx;
+ __le32 lease_flags;
};
struct cifs_fid {
@@ -1448,6 +1414,7 @@ struct cifs_fid {
__u64 persistent_fid; /* persist file id for smb2 */
__u64 volatile_fid; /* volatile file id for smb2 */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
+ __u8 parent_lease_key[SMB2_LEASE_KEY_SIZE];
__u8 create_guid[16];
__u32 access;
struct cifs_pending_open *pending_open;
@@ -1527,10 +1494,12 @@ struct cifs_io_subrequest {
int result;
bool have_xid;
bool replay;
+ unsigned int retries; /* number of retries so far */
+ unsigned int cur_sleep; /* time to sleep before replay */
struct kvec iov[2];
struct TCP_Server_Info *server;
#ifdef CONFIG_CIFS_SMB_DIRECT
- struct smbd_mr *mr;
+ struct smbdirect_mr_io *mr;
#endif
struct cifs_credits credits;
};
@@ -1546,9 +1515,14 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
}
struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
-void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_hdlr,
- bool offload);
+void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
+ bool wait_oplock_handler, bool offload);
void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
+int cifs_file_flush(const unsigned int xid, struct inode *inode,
+ struct cifsFileInfo *cfile);
+int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
+ const char *full_path, struct cifsFileInfo *open_file,
+ loff_t size);
#define CIFS_CACHE_READ_FLG 1
#define CIFS_CACHE_HANDLE_FLG 2
@@ -1557,13 +1531,16 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
-#define CIFS_CACHE_READ(cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE))
-#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
-#define CIFS_CACHE_WRITE(cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE))
-
-/*
- * One of these for each file inode
- */
+enum cifs_inode_flags {
+ CIFS_INODE_PENDING_OPLOCK_BREAK, /* oplock break in progress */
+ CIFS_INODE_PENDING_WRITERS, /* Writes in progress */
+ CIFS_INODE_FLAG_UNUSED, /* Unused flag */
+ CIFS_INO_DELETE_PENDING, /* delete pending on server */
+ CIFS_INO_INVALID_MAPPING, /* pagecache is invalid */
+ CIFS_INO_LOCK, /* lock bit for synchronization */
+ CIFS_INO_TMPFILE, /* for O_TMPFILE inodes */
+ CIFS_INO_CLOSE_ON_LOCK, /* Not to defer the close when lock is set */
+};
struct cifsInodeInfo {
struct netfs_inode netfs; /* Netfslib context and vfs inode */
@@ -1581,13 +1558,6 @@ struct cifsInodeInfo {
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
unsigned int oplock; /* oplock/lease level we have */
__u16 epoch; /* used to track lease state changes */
-#define CIFS_INODE_PENDING_OPLOCK_BREAK (0) /* oplock break in progress */
-#define CIFS_INODE_PENDING_WRITERS (1) /* Writes in progress */
-#define CIFS_INODE_FLAG_UNUSED (2) /* Unused flag */
-#define CIFS_INO_DELETE_PENDING (3) /* delete pending on server */
-#define CIFS_INO_INVALID_MAPPING (4) /* pagecache is invalid */
-#define CIFS_INO_LOCK (5) /* lock bit for synchronization */
-#define CIFS_INO_CLOSE_ON_LOCK (7) /* Not to defer the close when lock is set */
unsigned long flags;
spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */
@@ -1608,24 +1578,59 @@ CIFS_I(struct inode *inode)
return container_of(inode, struct cifsInodeInfo, netfs.inode);
}
-static inline struct cifs_sb_info *
-CIFS_SB(struct super_block *sb)
+static inline void *cinode_to_fsinfo(struct cifsInodeInfo *cinode)
+{
+ return cinode->netfs.inode.i_sb->s_fs_info;
+}
+
+static inline void *super_to_fsinfo(struct super_block *sb)
{
return sb->s_fs_info;
}
-static inline struct cifs_sb_info *
-CIFS_FILE_SB(struct file *file)
+static inline void *inode_to_fsinfo(struct inode *inode)
+{
+ return inode->i_sb->s_fs_info;
+}
+
+static inline void *file_to_fsinfo(struct file *file)
+{
+ return file_inode(file)->i_sb->s_fs_info;
+}
+
+static inline void *dentry_to_fsinfo(struct dentry *dentry)
+{
+ return dentry->d_sb->s_fs_info;
+}
+
+static inline void *const_dentry_to_fsinfo(const struct dentry *dentry)
{
- return CIFS_SB(file_inode(file)->i_sb);
+ return dentry->d_sb->s_fs_info;
+}
+
+#define CIFS_SB(_ptr) \
+ ((struct cifs_sb_info *) \
+ _Generic((_ptr), \
+ struct cifsInodeInfo * : cinode_to_fsinfo, \
+ const struct dentry * : const_dentry_to_fsinfo, \
+ struct super_block * : super_to_fsinfo, \
+ struct dentry * : dentry_to_fsinfo, \
+ struct inode * : inode_to_fsinfo, \
+ struct file * : file_to_fsinfo)(_ptr))
+
+/*
+ * Use atomic_t for @cifs_sb->mnt_cifs_flags as it is currently accessed
+ * locklessly and may be changed concurrently by mount/remount and reconnect
+ * paths.
+ */
+static inline unsigned int cifs_sb_flags(const struct cifs_sb_info *cifs_sb)
+{
+ return atomic_read(&cifs_sb->mnt_cifs_flags);
}
static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
- return '/';
- else
- return '\\';
+ return (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS) ? '/' : '\\';
}
static inline void
@@ -1676,7 +1681,7 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
* Returns zero on a successful receive, or an error. The receive state in
* the TCP_Server_Info will also be updated.
*/
-typedef int (mid_receive_t)(struct TCP_Server_Info *server,
+typedef int (*mid_receive_t)(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
/*
@@ -1687,42 +1692,45 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
* - it will be called by cifsd, with no locks held
* - the mid will be removed from any lists
*/
-typedef void (mid_callback_t)(struct mid_q_entry *mid);
+typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct mid_q_entry *mid);
/*
* This is the protopyte for mid handle function. This is called once the mid
* has been recognized after decryption of the message.
*/
-typedef int (mid_handle_t)(struct TCP_Server_Info *server,
+typedef int (*mid_handle_t)(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
/* one of these for every pending CIFS request to the server */
struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */
- struct kref refcount;
- struct TCP_Server_Info *server; /* server corresponding to this mid */
+ refcount_t refcount;
__u64 mid; /* multiplex id */
__u16 credits; /* number of credits consumed by this mid */
__u16 credits_received; /* number of credits from the response */
__u32 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */
+ unsigned int sr_flags; /* Flags passed to send_recv() */
unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */
#endif
- mid_receive_t *receive; /* call receive callback */
- mid_callback_t *callback; /* call completion callback */
- mid_handle_t *handle; /* call handle mid callback */
+ mid_receive_t receive; /* call receive callback */
+ mid_callback_t callback; /* call completion callback */
+ mid_handle_t handle; /* call handle mid callback */
void *callback_data; /* general purpose pointer for callback */
struct task_struct *creator;
void *resp_buf; /* pointer to received SMB header */
unsigned int resp_buf_size;
+ u32 response_pdu_len;
int mid_state; /* wish this were enum but can not pass to wait_event */
int mid_rc; /* rc for MID_RC */
- unsigned int mid_flags;
__le16 command; /* smb command code */
unsigned int optype; /* operation type */
+ spinlock_t mid_lock;
+ bool wait_cancelled:1; /* Cancelled while waiting for response */
+ bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */
bool large_buf:1; /* if valid response, is pointer to large buf */
bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */
@@ -1808,6 +1816,11 @@ struct cifs_mount_ctx {
struct cifs_tcon *tcon;
};
+struct mchan_mount {
+ struct work_struct work;
+ struct cifs_ses *ses;
+};
+
static inline void __free_dfs_info_param(struct dfs_info3_param *param)
{
kfree(param->path_name);
@@ -1869,10 +1882,13 @@ static inline bool is_replayable_error(int error)
}
-/* cifs_get_writable_file() flags */
-#define FIND_WR_ANY 0
-#define FIND_WR_FSUID_ONLY 1
-#define FIND_WR_WITH_DELETE 2
+enum cifs_find_flags {
+ FIND_ANY = 0U,
+ FIND_FSUID_ONLY = (1U << 0),
+ FIND_WITH_DELETE = (1U << 1),
+ FIND_NO_PENDING_DELETE = (1U << 2),
+ FIND_OPEN_FLAGS = (1U << 3),
+};
#define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1
@@ -1884,10 +1900,6 @@ static inline bool is_replayable_error(int error)
#define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
#define MID_RC 0x80 /* mid_rc contains custom rc */
-/* Flags */
-#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */
-#define MID_DELETED 2 /* Mid has been dequeued/deleted */
-
/* Types of response buffer returned from SendReceive2 */
#define CIFS_NO_BUFFER 0 /* Response buffer not returned */
#define CIFS_SMALL_BUFFER 1
@@ -1915,6 +1927,8 @@ static inline bool is_replayable_error(int error)
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
#define CIFS_NO_SRV_RSP 0x1000 /* there is no server response */
#define CIFS_COMPRESS_REQ 0x4000 /* compress request before sending */
+#define CIFS_INTERRUPTIBLE_WAIT 0x8000 /* Interruptible wait (e.g. lock request) */
+#define CIFS_WINDOWS_LOCK 0x10000 /* We're trying to get a Windows lock */
/* Security Flags: indicate type of session setup needed */
#define CIFSSEC_MAY_SIGN 0x00001
@@ -1954,6 +1968,8 @@ require use of the stronger protocol */
*/
/****************************************************************************
+ * LOCK ORDERING NOTES:
+ ****************************************************************************
* Here are all the locks (spinlock, mutex, semaphore) in cifs.ko, arranged according
* to the locking order. i.e. if two locks are to be held together, the lock that
* appears higher in this list needs to be taken before the other.
@@ -1982,50 +1998,61 @@ require use of the stronger protocol */
* =====================================================================================
* Lock Protects Initialization fn
* =====================================================================================
+ * cifs_mount_mutex mount/unmount operations
* vol_list_lock
* vol_info->ctx_lock vol_info->ctx
* cifs_sb_info->tlink_tree_lock cifs_sb_info->tlink_tree cifs_setup_cifs_sb
* TCP_Server_Info-> TCP_Server_Info cifs_get_tcp_session
* reconnect_mutex
+ * cifs_ses->session_mutex cifs_ses sesInfoAlloc
* TCP_Server_Info->srv_mutex TCP_Server_Info cifs_get_tcp_session
- * cifs_ses->session_mutex cifs_ses sesInfoAlloc
- * cifs_tcon
+ * cifs_tcp_ses_lock cifs_tcp_ses_list sesInfoAlloc
* cifs_tcon->open_file_lock cifs_tcon->openFileList tconInfoAlloc
* cifs_tcon->pending_opens
* cifs_tcon->stat_lock cifs_tcon->bytes_read tconInfoAlloc
* cifs_tcon->bytes_written
- * cifs_tcp_ses_lock cifs_tcp_ses_list sesInfoAlloc
+ * cifs_tcon->fscache_lock cifs_tcon->fscache tconInfoAlloc
+ * cifs_tcon->sb_list_lock cifs_tcon->cifs_sb_list tconInfoAlloc
* GlobalMid_Lock GlobalMaxActiveXid init_cifs
* GlobalCurrentXid
* GlobalTotalActiveXid
* TCP_Server_Info->srv_lock (anything in struct not protected by another lock and can change)
- * TCP_Server_Info->mid_lock TCP_Server_Info->pending_mid_q cifs_get_tcp_session
- * ->CurrentMid
- * (any changes in mid_q_entry fields)
+ * TCP_Server_Info->mid_queue_lock TCP_Server_Info->pending_mid_q cifs_get_tcp_session
+ * mid_q_entry->deleted_from_q
+ * TCP_Server_Info->mid_counter_lock TCP_Server_Info->current_mid cifs_get_tcp_session
* TCP_Server_Info->req_lock TCP_Server_Info->in_flight cifs_get_tcp_session
* ->credits
* ->echo_credits
* ->oplock_credits
* ->reconnect_instance
* cifs_ses->ses_lock (anything that is not protected by another lock and can change)
+ * sesInfoAlloc
* cifs_ses->iface_lock cifs_ses->iface_list sesInfoAlloc
* ->iface_count
* ->iface_last_update
- * cifs_ses->chan_lock cifs_ses->chans
+ * cifs_ses->chan_lock cifs_ses->chans sesInfoAlloc
* ->chans_need_reconnect
* ->chans_in_reconnect
* cifs_tcon->tc_lock (anything that is not protected by another lock and can change)
+ * tcon_info_alloc
+ * cifs_swnreg_idr_mutex cifs_swnreg_idr cifs_swn.c
+ * (witness service registration, accesses tcon fields under tc_lock)
* inode->i_rwsem, taken by fs/netfs/locking.c e.g. should be taken before cifsInodeInfo locks
* cifsInodeInfo->open_file_lock cifsInodeInfo->openFileList cifs_alloc_inode
* cifsInodeInfo->writers_lock cifsInodeInfo->writers cifsInodeInfo_alloc
* cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once
* ->can_cache_brlcks
* cifsInodeInfo->deferred_lock cifsInodeInfo->deferred_closes cifsInodeInfo_alloc
- * cached_fids->cfid_list_lock cifs_tcon->cfids->entries init_cached_dirs
- * cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo
+ * cached_fids->cfid_list_lock cifs_tcon->cfids->entries init_cached_dirs
+ * cached_fid->dirents.de_mutex cached_fid->dirents alloc_cached_dir
+ * cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
* ->invalidHandle initiate_cifs_search
* ->oplock_break_cancelled
+ * smbdirect_mr->mutex RDMA memory region management (SMBDirect only)
+ * mid_q_entry->mid_lock mid_q_entry->callback alloc_mid
+ * smb2_mid_entry_alloc
+ * (Any fields of mid_q_entry that will need protection)
****************************************************************************/
#ifdef DECLARE_GLOBALS_HERE
@@ -2114,35 +2141,23 @@ extern __u32 cifs_lock_secret;
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
-extern mempool_t *cifs_mid_poolp;
+extern mempool_t cifs_mid_pool;
extern mempool_t cifs_io_request_pool;
extern mempool_t cifs_io_subrequest_pool;
/* Operations for different SMB versions */
-#define SMB1_VERSION_STRING "1.0"
-#define SMB20_VERSION_STRING "2.0"
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-extern struct smb_version_operations smb1_operations;
-extern struct smb_version_values smb1_values;
extern struct smb_version_operations smb20_operations;
extern struct smb_version_values smb20_values;
-#endif /* CIFS_ALLOW_INSECURE_LEGACY */
-#define SMB21_VERSION_STRING "2.1"
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
extern struct smb_version_operations smb21_operations;
extern struct smb_version_values smb21_values;
-#define SMBDEFAULT_VERSION_STRING "default"
extern struct smb_version_values smbdefault_values;
-#define SMB3ANY_VERSION_STRING "3"
extern struct smb_version_values smb3any_values;
-#define SMB30_VERSION_STRING "3.0"
extern struct smb_version_operations smb30_operations;
extern struct smb_version_values smb30_values;
-#define SMB302_VERSION_STRING "3.02"
-#define ALT_SMB302_VERSION_STRING "3.0.2"
/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
extern struct smb_version_values smb302_values;
-#define SMB311_VERSION_STRING "3.1.1"
-#define ALT_SMB311_VERSION_STRING "3.11"
extern struct smb_version_operations smb311_operations;
extern struct smb_version_values smb311_values;
@@ -2222,94 +2237,6 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
dst->FileNameLength = src->FileNameLength;
}
-static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
- int num_rqst,
- const u8 *sig)
-{
- unsigned int len, skip;
- unsigned int nents = 0;
- unsigned long addr;
- size_t data_size;
- int i, j;
-
- /*
- * The first rqst has a transform header where the first 20 bytes are
- * not part of the encrypted blob.
- */
- skip = 20;
-
- /* Assumes the first rqst has a transform header as the first iov.
- * I.e.
- * rqst[0].rq_iov[0] is transform header
- * rqst[0].rq_iov[1+] data to be encrypted/decrypted
- * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
- */
- for (i = 0; i < num_rqst; i++) {
- data_size = iov_iter_count(&rqst[i].rq_iter);
-
- /* We really don't want a mixture of pinned and unpinned pages
- * in the sglist. It's hard to keep track of which is what.
- * Instead, we convert to a BVEC-type iterator higher up.
- */
- if (data_size &&
- WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
- return -EIO;
-
- /* We also don't want to have any extra refs or pins to clean
- * up in the sglist.
- */
- if (data_size &&
- WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
- return -EIO;
-
- for (j = 0; j < rqst[i].rq_nvec; j++) {
- struct kvec *iov = &rqst[i].rq_iov[j];
-
- addr = (unsigned long)iov->iov_base + skip;
- if (is_vmalloc_or_module_addr((void *)addr)) {
- len = iov->iov_len - skip;
- nents += DIV_ROUND_UP(offset_in_page(addr) + len,
- PAGE_SIZE);
- } else {
- nents++;
- }
- skip = 0;
- }
- if (data_size)
- nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
- }
- nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
- return nents;
-}
-
-/* We can not use the normal sg_set_buf() as we will sometimes pass a
- * stack object as buf.
- */
-static inline void cifs_sg_set_buf(struct sg_table *sgtable,
- const void *buf,
- unsigned int buflen)
-{
- unsigned long addr = (unsigned long)buf;
- unsigned int off = offset_in_page(addr);
-
- addr &= PAGE_MASK;
- if (is_vmalloc_or_module_addr((void *)addr)) {
- do {
- unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
-
- sg_set_page(&sgtable->sgl[sgtable->nents++],
- vmalloc_to_page((void *)addr), len, off);
-
- off = 0;
- addr += PAGE_SIZE;
- buflen -= len;
- } while (buflen);
- } else {
- sg_set_page(&sgtable->sgl[sgtable->nents++],
- virt_to_page((void *)addr), buflen, off);
- }
-}
-
#define CIFS_OPARMS(_cifs_sb, _tcon, _path, _da, _cd, _co, _mode) \
((struct cifs_open_parms) { \
.tcon = _tcon, \
@@ -2329,6 +2256,9 @@ struct smb2_compound_vars {
struct kvec qi_iov;
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
+ struct kvec hl_iov[SMB2_SET_INFO_IOV_SIZE];
+ struct kvec unlink_iov[SMB2_SET_INFO_IOV_SIZE];
+ struct kvec rename_iov[SMB2_SET_INFO_IOV_SIZE];
struct kvec close_iov;
struct smb2_file_rename_info_hdr rename_info;
struct smb2_file_link_info_hdr link_info;
@@ -2365,4 +2295,101 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen)
return ret;
}
+/*
+ * Execute mid callback atomically - ensures callback runs exactly once
+ * and prevents sleeping in atomic context.
+ */
+static inline void mid_execute_callback(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid)
+{
+ mid_callback_t callback;
+
+ spin_lock(&mid->mid_lock);
+ callback = mid->callback;
+ mid->callback = NULL; /* Mark as executed, */
+ spin_unlock(&mid->mid_lock);
+
+ if (callback)
+ callback(server, mid);
+}
+
+#define CIFS_REPARSE_SUPPORT(tcon) \
+ ((tcon)->posix_extensions || \
+ (le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \
+ FILE_SUPPORTS_REPARSE_POINTS))
+
+struct cifs_calc_sig_ctx {
+ struct md5_ctx *md5;
+ struct hmac_sha256_ctx *hmac;
+ struct aes_cmac_ctx *cmac;
+};
+
+#define CIFS_RECONN_DELAY_SECS 30
+#define CIFS_MAX_RECONN_DELAY (4 * CIFS_RECONN_DELAY_SECS)
+
+static inline void cifs_queue_server_reconn(struct TCP_Server_Info *server)
+{
+ if (!delayed_work_pending(&server->reconnect)) {
+ WRITE_ONCE(server->reconn_delay, 0);
+ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ }
+}
+
+static inline void cifs_requeue_server_reconn(struct TCP_Server_Info *server)
+{
+ unsigned long delay = READ_ONCE(server->reconn_delay);
+
+ delay = umin(delay + CIFS_RECONN_DELAY_SECS, CIFS_MAX_RECONN_DELAY);
+ WRITE_ONCE(server->reconn_delay, delay);
+ queue_delayed_work(cifsiod_wq, &server->reconnect, delay * HZ);
+}
+
+static inline bool __cifs_cache_state_check(struct cifsInodeInfo *cinode,
+ unsigned int oplock_flags,
+ unsigned int sb_flags)
+{
+ unsigned int sflags = cifs_sb_flags(CIFS_SB(cinode));
+ unsigned int oplock = READ_ONCE(cinode->oplock);
+
+ return (oplock & oplock_flags) || (sflags & sb_flags);
+}
+
+#define CIFS_CACHE_READ(cinode) \
+ __cifs_cache_state_check(cinode, CIFS_CACHE_READ_FLG, \
+ CIFS_MOUNT_RO_CACHE)
+#define CIFS_CACHE_HANDLE(cinode) \
+ __cifs_cache_state_check(cinode, CIFS_CACHE_HANDLE_FLG, 0)
+#define CIFS_CACHE_WRITE(cinode) \
+ __cifs_cache_state_check(cinode, CIFS_CACHE_WRITE_FLG, \
+ CIFS_MOUNT_RW_CACHE)
+
+static inline void cifs_reset_oplock(struct cifsInodeInfo *cinode)
+{
+ scoped_guard(spinlock, &cinode->open_file_lock)
+ WRITE_ONCE(cinode->oplock, 0);
+}
+
+static inline bool cifs_forced_shutdown(const struct cifs_sb_info *sbi)
+{
+ return cifs_sb_flags(sbi) & CIFS_MOUNT_SHUTDOWN;
+}
+
+static inline int cifs_open_create_options(unsigned int oflags, int opts)
+{
+ /* O_SYNC also has bit for O_DSYNC so following check picks up either */
+ if (oflags & O_SYNC)
+ opts |= CREATE_WRITE_THROUGH;
+ if (oflags & O_DIRECT)
+ opts |= CREATE_NO_BUFFER;
+ if (oflags & O_TMPFILE)
+ opts |= CREATE_DELETE_ON_CLOSE;
+ return opts;
+}
+
+/*
+ * The number of blocks is not related to (i_size / i_blksize), but instead
+ * 512 byte (2**9) size is required for calculating num blocks.
+ */
+#define CIFS_INO_BLOCKS(size) DIV_ROUND_UP_ULL((u64)(size), 512)
+
#endif /* _CIFS_GLOB_H */
diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h
index 18d67ab113f0..78512af18d96 100644
--- a/fs/smb/client/cifspdu.h
+++ b/fs/smb/client/cifspdu.h
@@ -9,2714 +9,4 @@
#ifndef _CIFSPDU_H
#define _CIFSPDU_H
-#include <net/sock.h>
-#include <linux/unaligned.h>
-#include "../common/smbfsctl.h"
-
-#define CIFS_PROT 0
-#define POSIX_PROT (CIFS_PROT+1)
-#define BAD_PROT 0xFFFF
-
-/* SMB command codes:
- * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses
- * (ie which include no useful data other than the SMB error code itself).
- * This can allow us to avoid response buffer allocations and copy in some cases
- */
-#define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */
-#define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */
-#define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */
-#define SMB_COM_FLUSH 0x05 /* triv req/rsp */
-#define SMB_COM_DELETE 0x06 /* trivial response */
-#define SMB_COM_RENAME 0x07 /* trivial response */
-#define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */
-#define SMB_COM_SETATTR 0x09 /* trivial response */
-#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
-#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
-#define SMB_COM_ECHO 0x2B /* echo request */
-#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
-#define SMB_COM_READ_ANDX 0x2E
-#define SMB_COM_WRITE_ANDX 0x2F
-#define SMB_COM_TRANSACTION2 0x32
-#define SMB_COM_TRANSACTION2_SECONDARY 0x33
-#define SMB_COM_FIND_CLOSE2 0x34 /* trivial response */
-#define SMB_COM_TREE_DISCONNECT 0x71 /* trivial response */
-#define SMB_COM_NEGOTIATE 0x72
-#define SMB_COM_SESSION_SETUP_ANDX 0x73
-#define SMB_COM_LOGOFF_ANDX 0x74 /* trivial response */
-#define SMB_COM_TREE_CONNECT_ANDX 0x75
-#define SMB_COM_NT_TRANSACT 0xA0
-#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
-#define SMB_COM_NT_CREATE_ANDX 0xA2
-#define SMB_COM_NT_CANCEL 0xA4 /* no response */
-#define SMB_COM_NT_RENAME 0xA5 /* trivial response */
-
-/* Transact2 subcommand codes */
-#define TRANS2_OPEN 0x00
-#define TRANS2_FIND_FIRST 0x01
-#define TRANS2_FIND_NEXT 0x02
-#define TRANS2_QUERY_FS_INFORMATION 0x03
-#define TRANS2_SET_FS_INFORMATION 0x04
-#define TRANS2_QUERY_PATH_INFORMATION 0x05
-#define TRANS2_SET_PATH_INFORMATION 0x06
-#define TRANS2_QUERY_FILE_INFORMATION 0x07
-#define TRANS2_SET_FILE_INFORMATION 0x08
-#define TRANS2_GET_DFS_REFERRAL 0x10
-#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
-
-/* SMB Transact (Named Pipe) subcommand codes */
-#define TRANS_SET_NMPIPE_STATE 0x0001
-#define TRANS_RAW_READ_NMPIPE 0x0011
-#define TRANS_QUERY_NMPIPE_STATE 0x0021
-#define TRANS_QUERY_NMPIPE_INFO 0x0022
-#define TRANS_PEEK_NMPIPE 0x0023
-#define TRANS_TRANSACT_NMPIPE 0x0026
-#define TRANS_RAW_WRITE_NMPIPE 0x0031
-#define TRANS_READ_NMPIPE 0x0036
-#define TRANS_WRITE_NMPIPE 0x0037
-#define TRANS_WAIT_NMPIPE 0x0053
-#define TRANS_CALL_NMPIPE 0x0054
-
-/* NT Transact subcommand codes */
-#define NT_TRANSACT_CREATE 0x01
-#define NT_TRANSACT_IOCTL 0x02
-#define NT_TRANSACT_SET_SECURITY_DESC 0x03
-#define NT_TRANSACT_NOTIFY_CHANGE 0x04
-#define NT_TRANSACT_RENAME 0x05
-#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06
-#define NT_TRANSACT_GET_USER_QUOTA 0x07
-#define NT_TRANSACT_SET_USER_QUOTA 0x08
-
-#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
-/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
-/* among the requests (NTCreateX response is bigger with wct of 34) */
-#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
-#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
-
-/* internal cifs vfs structures */
-/*****************************************************************
- * All constants go here
- *****************************************************************
- */
-
-/*
- * Starting value for maximum SMB size negotiation
- */
-#define CIFS_MAX_MSGSIZE (4*4096)
-
-/*
- * Size of encrypted user password in bytes
- */
-#define CIFS_ENCPWD_SIZE (16)
-
-/*
- * Size of the crypto key returned on the negotiate SMB in bytes
- */
-#define CIFS_CRYPTO_KEY_SIZE (8)
-
-/*
- * Size of the ntlm client response
- */
-#define CIFS_AUTH_RESP_SIZE (24)
-
-/*
- * Size of the session key (crypto key encrypted with the password
- */
-#define CIFS_SESS_KEY_SIZE (16)
-
-#define CIFS_SERVER_CHALLENGE_SIZE (8)
-#define CIFS_HMAC_MD5_HASH_SIZE (16)
-#define CIFS_CPHTXT_SIZE (16)
-#define CIFS_NTHASH_SIZE (16)
-
-/*
- * Maximum user name length
- */
-#define CIFS_UNLEN (20)
-
-/*
- * Flags on SMB open
- */
-#define SMBOPEN_WRITE_THROUGH 0x4000
-#define SMBOPEN_DENY_ALL 0x0010
-#define SMBOPEN_DENY_WRITE 0x0020
-#define SMBOPEN_DENY_READ 0x0030
-#define SMBOPEN_DENY_NONE 0x0040
-#define SMBOPEN_READ 0x0000
-#define SMBOPEN_WRITE 0x0001
-#define SMBOPEN_READWRITE 0x0002
-#define SMBOPEN_EXECUTE 0x0003
-
-#define SMBOPEN_OCREATE 0x0010
-#define SMBOPEN_OTRUNC 0x0002
-#define SMBOPEN_OAPPEND 0x0001
-
-/*
- * SMB flag definitions
- */
-#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */
-#define SMBFLG_RCV_POSTED 0x02 /* obsolete */
-#define SMBFLG_RSVD 0x04
-#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off
- implies case sensitive file handling request) */
-#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */
-#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */
-#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */
-#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
-
-/*
- * SMB flag2 definitions
- */
-#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3)
- path names in response */
-#define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
-#define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
-#define SMBFLG2_COMPRESSED (8)
-#define SMBFLG2_SECURITY_SIGNATURE_REQUIRED (0x10)
-#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
-#define SMBFLG2_REPARSE_PATH (0x400)
-#define SMBFLG2_EXT_SEC cpu_to_le16(0x800)
-#define SMBFLG2_DFS cpu_to_le16(0x1000)
-#define SMBFLG2_PAGING_IO cpu_to_le16(0x2000)
-#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000)
-#define SMBFLG2_UNICODE cpu_to_le16(0x8000)
-
-/*
- * These are the file access permission bits defined in CIFS for the
- * NTCreateAndX as well as the level 0x107
- * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO
- * responds with the AccessFlags.
- * The AccessFlags specifies the access permissions a caller has to the
- * file and can have any suitable combination of the following values:
- */
-
-#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */
- /* or directory child entries can */
- /* be listed together with the */
- /* associated child attributes */
- /* (so the FILE_READ_ATTRIBUTES on */
- /* the child entry is not needed) */
-#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */
- /* or new file can be created in */
- /* the directory */
-#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */
- /* (for non-local files over SMB it */
- /* is same as FILE_WRITE_DATA) */
- /* or new subdirectory can be */
- /* created in the directory */
-#define FILE_READ_EA 0x00000008 /* Extended attributes associated */
- /* with the file can be read */
-#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */
- /* with the file can be written */
-#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */
- /* the file using system paging I/O */
- /* for executing the file / script */
- /* or right to traverse directory */
- /* (but by default all users have */
- /* directory bypass traverse */
- /* privilege and do not need this */
- /* permission on directories at all)*/
-#define FILE_DELETE_CHILD 0x00000040 /* Child entry can be deleted from */
- /* the directory (so the DELETE on */
- /* the child entry is not needed) */
-#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */
- /* file or directory can be read */
-#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */
- /* file or directory can be written */
-#define DELETE 0x00010000 /* The file or dir can be deleted */
-#define READ_CONTROL 0x00020000 /* The discretionary access control */
- /* list and ownership associated */
- /* with the file or dir can be read */
-#define WRITE_DAC 0x00040000 /* The discretionary access control */
- /* list associated with the file or */
- /* directory can be written */
-#define WRITE_OWNER 0x00080000 /* Ownership information associated */
- /* with the file/dir can be written */
-#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */
- /* synchronize with the completion */
- /* of an input/output request */
-#define SYSTEM_SECURITY 0x01000000 /* The system access control list */
- /* associated with the file or */
- /* directory can be read or written */
- /* (cannot be in DACL, can in SACL) */
-#define MAXIMUM_ALLOWED 0x02000000 /* Maximal subset of GENERIC_ALL */
- /* permissions which can be granted */
- /* (cannot be in DACL nor SACL) */
-#define GENERIC_ALL 0x10000000 /* Same as: GENERIC_EXECUTE | */
- /* GENERIC_WRITE | */
- /* GENERIC_READ | */
- /* FILE_DELETE_CHILD | */
- /* DELETE | */
- /* WRITE_DAC | */
- /* WRITE_OWNER */
- /* So GENERIC_ALL contains all bits */
- /* mentioned above except these two */
- /* SYSTEM_SECURITY MAXIMUM_ALLOWED */
-#define GENERIC_EXECUTE 0x20000000 /* Same as: FILE_EXECUTE | */
- /* FILE_READ_ATTRIBUTES | */
- /* READ_CONTROL | */
- /* SYNCHRONIZE */
-#define GENERIC_WRITE 0x40000000 /* Same as: FILE_WRITE_DATA | */
- /* FILE_APPEND_DATA | */
- /* FILE_WRITE_EA | */
- /* FILE_WRITE_ATTRIBUTES | */
- /* READ_CONTROL | */
- /* SYNCHRONIZE */
-#define GENERIC_READ 0x80000000 /* Same as: FILE_READ_DATA | */
- /* FILE_READ_EA | */
- /* FILE_READ_ATTRIBUTES | */
- /* READ_CONTROL | */
- /* SYNCHRONIZE */
-
-#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES)
-#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
- | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
-#define FILE_EXEC_RIGHTS (FILE_EXECUTE)
-
-#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \
- | FILE_READ_ATTRIBUTES \
- | FILE_WRITE_ATTRIBUTES \
- | DELETE | READ_CONTROL | WRITE_DAC \
- | WRITE_OWNER | SYNCHRONIZE)
-#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
- | FILE_READ_EA | FILE_WRITE_EA \
- | FILE_READ_ATTRIBUTES \
- | FILE_WRITE_ATTRIBUTES \
- | DELETE | READ_CONTROL | WRITE_DAC \
- | WRITE_OWNER | SYNCHRONIZE)
-#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \
- | FILE_READ_ATTRIBUTES \
- | FILE_WRITE_ATTRIBUTES \
- | DELETE | READ_CONTROL | WRITE_DAC \
- | WRITE_OWNER | SYNCHRONIZE)
-
-#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
- | READ_CONTROL | SYNCHRONIZE)
-
-
-/*
- * Invalid readdir handle
- */
-#define CIFS_NO_HANDLE 0xFFFF
-
-#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
-
-/* IPC$ in ASCII */
-#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
-
-/* IPC$ in Unicode */
-#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00"
-
-/* Unicode Null terminate 2 bytes of 0 */
-#define UNICODE_NULL "\x00\x00"
-#define ASCII_NULL 0x00
-
-/*
- * Server type values (returned on EnumServer API
- */
-#define CIFS_SV_TYPE_DC 0x00000008
-#define CIFS_SV_TYPE_BACKDC 0x00000010
-
-/*
- * Alias type flags (From EnumAlias API call
- */
-#define CIFS_ALIAS_TYPE_FILE 0x0001
-#define CIFS_SHARE_TYPE_FILE 0x0000
-
-/*
- * File Attribute flags
- */
-#define ATTR_READONLY 0x0001
-#define ATTR_HIDDEN 0x0002
-#define ATTR_SYSTEM 0x0004
-#define ATTR_VOLUME 0x0008
-#define ATTR_DIRECTORY 0x0010
-#define ATTR_ARCHIVE 0x0020
-#define ATTR_DEVICE 0x0040
-#define ATTR_NORMAL 0x0080
-#define ATTR_TEMPORARY 0x0100
-#define ATTR_SPARSE 0x0200
-#define ATTR_REPARSE 0x0400
-#define ATTR_COMPRESSED 0x0800
-#define ATTR_OFFLINE 0x1000 /* ie file not immediately available -
- on offline storage */
-#define ATTR_NOT_CONTENT_INDEXED 0x2000
-#define ATTR_ENCRYPTED 0x4000
-#define ATTR_POSIX_SEMANTICS 0x01000000
-#define ATTR_BACKUP_SEMANTICS 0x02000000
-#define ATTR_DELETE_ON_CLOSE 0x04000000
-#define ATTR_SEQUENTIAL_SCAN 0x08000000
-#define ATTR_RANDOM_ACCESS 0x10000000
-#define ATTR_NO_BUFFERING 0x20000000
-#define ATTR_WRITE_THROUGH 0x80000000
-
-/* ShareAccess flags */
-#define FILE_NO_SHARE 0x00000000
-#define FILE_SHARE_READ 0x00000001
-#define FILE_SHARE_WRITE 0x00000002
-#define FILE_SHARE_DELETE 0x00000004
-#define FILE_SHARE_ALL 0x00000007
-
-/* CreateDisposition flags, similar to CreateAction as well */
-#define FILE_SUPERSEDE 0x00000000
-#define FILE_OPEN 0x00000001
-#define FILE_CREATE 0x00000002
-#define FILE_OPEN_IF 0x00000003
-#define FILE_OVERWRITE 0x00000004
-#define FILE_OVERWRITE_IF 0x00000005
-
-/* CreateOptions */
-#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
-#define CREATE_WRITE_THROUGH 0x00000002
-#define CREATE_SEQUENTIAL 0x00000004
-#define CREATE_NO_BUFFER 0x00000008 /* should not buffer on srv */
-#define CREATE_SYNC_ALERT 0x00000010 /* MBZ */
-#define CREATE_ASYNC_ALERT 0x00000020 /* MBZ */
-#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
-#define CREATE_TREE_CONNECTION 0x00000080 /* should be zero */
-#define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */
-#define CREATE_NO_EA_KNOWLEDGE 0x00000200
-#define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete
- "open for recovery" flag should
- be zero in any case */
-#define CREATE_OPEN_FOR_RECOVERY 0x00000400
-#define CREATE_RANDOM_ACCESS 0x00000800
-#define CREATE_DELETE_ON_CLOSE 0x00001000
-#define CREATE_OPEN_BY_ID 0x00002000
-#define CREATE_OPEN_BACKUP_INTENT 0x00004000
-#define CREATE_NO_COMPRESSION 0x00008000
-#define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */
-#define OPEN_REPARSE_POINT 0x00200000
-#define OPEN_NO_RECALL 0x00400000
-#define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */
-#define CREATE_OPTIONS_MASK 0x007FFFFF
-#define CREATE_OPTION_READONLY 0x10000000
-#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
-
-/* ImpersonationLevel flags */
-#define SECURITY_ANONYMOUS 0
-#define SECURITY_IDENTIFICATION 1
-#define SECURITY_IMPERSONATION 2
-#define SECURITY_DELEGATION 3
-
-/* SecurityFlags */
-#define SECURITY_CONTEXT_TRACKING 0x01
-#define SECURITY_EFFECTIVE_ONLY 0x02
-
-/*
- * Default PID value, used in all SMBs where the PID is not important
- */
-#define CIFS_DFT_PID 0x1234
-
-/*
- * We use the same routine for Copy and Move SMBs. This flag is used to
- * distinguish
- */
-#define CIFS_COPY_OP 1
-#define CIFS_RENAME_OP 2
-
-#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */
-#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */
-
-struct smb_hdr {
- __be32 smb_buf_length; /* BB length is only two (rarely three) bytes,
- with one or two byte "type" preceding it that will be
- zero - we could mask the type byte off */
- __u8 Protocol[4];
- __u8 Command;
- union {
- struct {
- __u8 ErrorClass;
- __u8 Reserved;
- __le16 Error;
- } __attribute__((packed)) DosError;
- __le32 CifsError;
- } __attribute__((packed)) Status;
- __u8 Flags;
- __le16 Flags2; /* note: le */
- __le16 PidHigh;
- union {
- struct {
- __le32 SequenceNumber; /* le */
- __u32 Reserved; /* zero */
- } __attribute__((packed)) Sequence;
- __u8 SecuritySignature[8]; /* le */
- } __attribute__((packed)) Signature;
- __u8 pad[2];
- __u16 Tid;
- __le16 Pid;
- __u16 Uid;
- __le16 Mid;
- __u8 WordCount;
-} __attribute__((packed));
-
-/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
-static inline void *
-BCC(struct smb_hdr *smb)
-{
- return (void *)smb + sizeof(*smb) + 2 * smb->WordCount;
-}
-
-/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
-#define pByteArea(smb_var) (BCC(smb_var) + 2)
-
-/* get the unconverted ByteCount for a SMB packet and return it */
-static inline __u16
-get_bcc(struct smb_hdr *hdr)
-{
- __le16 *bc_ptr = (__le16 *)BCC(hdr);
-
- return get_unaligned_le16(bc_ptr);
-}
-
-/* set the ByteCount for a SMB packet in little-endian */
-static inline void
-put_bcc(__u16 count, struct smb_hdr *hdr)
-{
- __le16 *bc_ptr = (__le16 *)BCC(hdr);
-
- put_unaligned_le16(count, bc_ptr);
-}
-
-/*
- * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
- * No longer as important, now that TCP names are more commonly used to
- * resolve hosts.
- */
-#define CNLEN 15
-
-/*
- * Share Name Length (SNLEN)
- * Note: This length was limited by the SMB used to get
- * the Share info. NetShareEnum only returned 13
- * chars, including the null termination.
- * This was removed because it no longer is limiting.
- */
-
-/*
- * Comment Length
- */
-#define MAXCOMMENTLEN 40
-
-/*
- * The OS/2 maximum path name
- */
-#define MAX_PATHCONF 256
-
-/*
- * SMB frame definitions (following must be packed structs)
- * See the SNIA CIFS Specification for details.
- *
- * The Naming convention is the lower case version of the
- * smb command code name for the struct and this is typedef to the
- * uppercase version of the same name with the prefix SMB_ removed
- * for brevity. Although typedefs are not commonly used for
- * structure definitions in the Linux kernel, their use in the
- * CIFS standards document, which this code is based on, may
- * make this one of the cases where typedefs for structures make
- * sense to improve readability for readers of the standards doc.
- * Typedefs can always be removed later if they are too distracting
- * and they are only used for the CIFSs PDUs themselves, not
- * internal cifs vfs structures
- *
- */
-
-typedef struct negotiate_req {
- struct smb_hdr hdr; /* wct = 0 */
- __le16 ByteCount;
- unsigned char DialectsArray[];
-} __attribute__((packed)) NEGOTIATE_REQ;
-
-#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
-
-#define READ_RAW_ENABLE 1
-#define WRITE_RAW_ENABLE 2
-#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
-#define SMB1_CLIENT_GUID_SIZE (16)
-typedef struct negotiate_rsp {
- struct smb_hdr hdr; /* wct = 17 */
- __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
- __u8 SecurityMode;
- __le16 MaxMpxCount;
- __le16 MaxNumberVcs;
- __le32 MaxBufferSize;
- __le32 MaxRawSize;
- __le32 SessionKey;
- __le32 Capabilities; /* see below */
- __le32 SystemTimeLow;
- __le32 SystemTimeHigh;
- __le16 ServerTimeZone;
- __u8 EncryptionKeyLength;
- __u16 ByteCount;
- union {
- /* cap extended security off */
- DECLARE_FLEX_ARRAY(unsigned char, EncryptionKey);
- /* followed by Domain name - if extended security is off */
- /* followed by 16 bytes of server GUID */
- /* then security blob if cap_extended_security negotiated */
- struct {
- unsigned char GUID[SMB1_CLIENT_GUID_SIZE];
- unsigned char SecurityBlob[];
- } __attribute__((packed)) extended_response;
- } __attribute__((packed)) u;
-} __attribute__((packed)) NEGOTIATE_RSP;
-
-/* SecurityMode bits */
-#define SECMODE_USER 0x01 /* off indicates share level security */
-#define SECMODE_PW_ENCRYPT 0x02
-#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */
-#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */
-
-/* Negotiate response Capabilities */
-#define CAP_RAW_MODE 0x00000001
-#define CAP_MPX_MODE 0x00000002
-#define CAP_UNICODE 0x00000004
-#define CAP_LARGE_FILES 0x00000008
-#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */
-#define CAP_RPC_REMOTE_APIS 0x00000020
-#define CAP_STATUS32 0x00000040
-#define CAP_LEVEL_II_OPLOCKS 0x00000080
-#define CAP_LOCK_AND_READ 0x00000100
-#define CAP_NT_FIND 0x00000200
-#define CAP_DFS 0x00001000
-#define CAP_INFOLEVEL_PASSTHRU 0x00002000
-#define CAP_LARGE_READ_X 0x00004000
-#define CAP_LARGE_WRITE_X 0x00008000
-#define CAP_LWIO 0x00010000 /* support fctl_srv_req_resume_key */
-#define CAP_UNIX 0x00800000
-#define CAP_COMPRESSED_DATA 0x02000000
-#define CAP_DYNAMIC_REAUTH 0x20000000
-#define CAP_PERSISTENT_HANDLES 0x40000000
-#define CAP_EXTENDED_SECURITY 0x80000000
-
-typedef union smb_com_session_setup_andx {
- struct { /* request format */
- struct smb_hdr hdr; /* wct = 12 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 MaxBufferSize;
- __le16 MaxMpxCount;
- __le16 VcNumber;
- __u32 SessionKey;
- __le16 SecurityBlobLength;
- __u32 Reserved;
- __le32 Capabilities; /* see below */
- __le16 ByteCount;
- unsigned char SecurityBlob[]; /* followed by */
- /* STRING NativeOS */
- /* STRING NativeLanMan */
- } __attribute__((packed)) req; /* NTLM request format (with
- extended security */
-
- struct { /* request format */
- struct smb_hdr hdr; /* wct = 13 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 MaxBufferSize;
- __le16 MaxMpxCount;
- __le16 VcNumber;
- __u32 SessionKey;
- __le16 CaseInsensitivePasswordLength; /* ASCII password len */
- __le16 CaseSensitivePasswordLength; /* Unicode password length*/
- __u32 Reserved; /* see below */
- __le32 Capabilities;
- __le16 ByteCount;
- unsigned char CaseInsensitivePassword[]; /* followed by: */
- /* unsigned char * CaseSensitivePassword; */
- /* STRING AccountName */
- /* STRING PrimaryDomain */
- /* STRING NativeOS */
- /* STRING NativeLanMan */
- } __attribute__((packed)) req_no_secext; /* NTLM request format (without
- extended security */
-
- struct { /* default (NTLM) response format */
- struct smb_hdr hdr; /* wct = 4 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 Action; /* see below */
- __le16 SecurityBlobLength;
- __u16 ByteCount;
- unsigned char SecurityBlob[]; /* followed by */
-/* unsigned char * NativeOS; */
-/* unsigned char * NativeLanMan; */
-/* unsigned char * PrimaryDomain; */
- } __attribute__((packed)) resp; /* NTLM response
- (with or without extended sec) */
-
- struct { /* request format */
- struct smb_hdr hdr; /* wct = 10 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 MaxBufferSize;
- __le16 MaxMpxCount;
- __le16 VcNumber;
- __u32 SessionKey;
- __le16 PasswordLength;
- __u32 Reserved; /* encrypt key len and offset */
- __le16 ByteCount;
- unsigned char AccountPassword[]; /* followed by */
- /* STRING AccountName */
- /* STRING PrimaryDomain */
- /* STRING NativeOS */
- /* STRING NativeLanMan */
- } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */
-
- struct { /* default (NTLM) response format */
- struct smb_hdr hdr; /* wct = 3 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 Action; /* see below */
- __u16 ByteCount;
- unsigned char NativeOS[]; /* followed by */
-/* unsigned char * NativeLanMan; */
-/* unsigned char * PrimaryDomain; */
- } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
-} __attribute__((packed)) SESSION_SETUP_ANDX;
-
-/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
-
-#define NTLMSSP_SERVER_TYPE 1
-#define NTLMSSP_DOMAIN_TYPE 2
-#define NTLMSSP_FQ_DOMAIN_TYPE 3
-#define NTLMSSP_DNS_DOMAIN_TYPE 4
-#define NTLMSSP_DNS_PARENT_TYPE 5
-
-struct ntlmssp2_name {
- __le16 type;
- __le16 length;
- __u8 data[];
-} __attribute__((packed));
-
-struct ntlmv2_resp {
- union {
- char ntlmv2_hash[CIFS_ENCPWD_SIZE];
- struct {
- __u8 reserved[8];
- __u8 key[CIFS_SERVER_CHALLENGE_SIZE];
- } __attribute__((packed)) challenge;
- } __attribute__((packed));
- __le32 blob_signature;
- __u32 reserved;
- __le64 time;
- __u64 client_chal; /* random */
- __u32 reserved2;
- /* array of name entries could follow ending in minimum 4 byte struct */
-} __attribute__((packed));
-
-
-#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
-
-/* Capabilities bits (for NTLM SessSetup request) */
-#define CAP_UNICODE 0x00000004
-#define CAP_LARGE_FILES 0x00000008
-#define CAP_NT_SMBS 0x00000010
-#define CAP_STATUS32 0x00000040
-#define CAP_LEVEL_II_OPLOCKS 0x00000080
-#define CAP_NT_FIND 0x00000200 /* reserved should be zero
- (because NT_SMBs implies the same thing?) */
-#define CAP_BULK_TRANSFER 0x20000000
-#define CAP_EXTENDED_SECURITY 0x80000000
-
-/* Action bits */
-#define GUEST_LOGIN 1
-
-typedef struct smb_com_tconx_req {
- struct smb_hdr hdr; /* wct = 4 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 Flags; /* see below */
- __le16 PasswordLength;
- __le16 ByteCount;
- unsigned char Password[]; /* followed by */
-/* STRING Path *//* \\server\share name */
- /* STRING Service */
-} __attribute__((packed)) TCONX_REQ;
-
-typedef struct smb_com_tconx_rsp {
- struct smb_hdr hdr; /* wct = 3 , not extended response */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 OptionalSupport; /* see below */
- __u16 ByteCount;
- unsigned char Service[]; /* always ASCII, not Unicode */
- /* STRING NativeFileSystem */
-} __attribute__((packed)) TCONX_RSP;
-
-typedef struct smb_com_tconx_rsp_ext {
- struct smb_hdr hdr; /* wct = 7, extended response */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 OptionalSupport; /* see below */
- __le32 MaximalShareAccessRights;
- __le32 GuestMaximalShareAccessRights;
- __u16 ByteCount;
- unsigned char Service[]; /* always ASCII, not Unicode */
- /* STRING NativeFileSystem */
-} __attribute__((packed)) TCONX_RSP_EXT;
-
-
-/* tree connect Flags */
-#define DISCONNECT_TID 0x0001
-#define TCON_EXTENDED_SIGNATURES 0x0004
-#define TCON_EXTENDED_SECINFO 0x0008
-
-/* OptionalSupport bits */
-#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits
- (exclusive searches supported) */
-#define SMB_SHARE_IS_IN_DFS 0x0002
-#define SMB_CSC_MASK 0x000C
-/* CSC flags defined as follows */
-#define SMB_CSC_CACHE_MANUAL_REINT 0x0000
-#define SMB_CSC_CACHE_AUTO_REINT 0x0004
-#define SMB_CSC_CACHE_VDO 0x0008
-#define SMB_CSC_NO_CACHING 0x000C
-#define SMB_UNIQUE_FILE_NAME 0x0010
-#define SMB_EXTENDED_SIGNATURES 0x0020
-
-/* services
- *
- * A: ie disk
- * LPT1: ie printer
- * IPC ie named pipe
- * COMM
- * ????? ie any type
- *
- */
-
-typedef struct smb_com_echo_req {
- struct smb_hdr hdr;
- __le16 EchoCount;
- __le16 ByteCount;
- char Data[];
-} __attribute__((packed)) ECHO_REQ;
-
-typedef struct smb_com_echo_rsp {
- struct smb_hdr hdr;
- __le16 SequenceNumber;
- __le16 ByteCount;
- char Data[];
-} __attribute__((packed)) ECHO_RSP;
-
-typedef struct smb_com_logoff_andx_req {
- struct smb_hdr hdr; /* wct = 2 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __u16 AndXOffset;
- __u16 ByteCount;
-} __attribute__((packed)) LOGOFF_ANDX_REQ;
-
-typedef struct smb_com_logoff_andx_rsp {
- struct smb_hdr hdr; /* wct = 2 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __u16 AndXOffset;
- __u16 ByteCount;
-} __attribute__((packed)) LOGOFF_ANDX_RSP;
-
-typedef union smb_com_tree_disconnect { /* as an alternative can use flag on
- tree_connect PDU to effect disconnect */
- /* tdis is probably simplest SMB PDU */
- struct {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bcc = 0 */
- } __attribute__((packed)) req;
- struct {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bcc = 0 */
- } __attribute__((packed)) resp;
-} __attribute__((packed)) TREE_DISCONNECT;
-
-typedef struct smb_com_close_req {
- struct smb_hdr hdr; /* wct = 3 */
- __u16 FileID;
- __u32 LastWriteTime; /* should be zero or -1 */
- __u16 ByteCount; /* 0 */
-} __attribute__((packed)) CLOSE_REQ;
-
-typedef struct smb_com_close_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) CLOSE_RSP;
-
-typedef struct smb_com_flush_req {
- struct smb_hdr hdr; /* wct = 1 */
- __u16 FileID;
- __u16 ByteCount; /* 0 */
-} __attribute__((packed)) FLUSH_REQ;
-
-typedef struct smb_com_findclose_req {
- struct smb_hdr hdr; /* wct = 1 */
- __u16 FileID;
- __u16 ByteCount; /* 0 */
-} __attribute__((packed)) FINDCLOSE_REQ;
-
-/* OpenFlags */
-#define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */
-#define REQ_OPLOCK 0x00000002
-#define REQ_BATCHOPLOCK 0x00000004
-#define REQ_OPENDIRONLY 0x00000008
-#define REQ_EXTENDED_INFO 0x00000010
-
-/* File type */
-#define DISK_TYPE 0x0000
-#define BYTE_PIPE_TYPE 0x0001
-#define MESSAGE_PIPE_TYPE 0x0002
-#define PRINTER_TYPE 0x0003
-#define COMM_DEV_TYPE 0x0004
-#define UNKNOWN_TYPE 0xFFFF
-
-/* Device Type or File Status Flags */
-#define NO_EAS 0x0001
-#define NO_SUBSTREAMS 0x0002
-#define NO_REPARSETAG 0x0004
-/* following flags can apply if pipe */
-#define ICOUNT_MASK 0x00FF
-#define PIPE_READ_MODE 0x0100
-#define NAMED_PIPE_TYPE 0x0400
-#define PIPE_END_POINT 0x4000
-#define BLOCKING_NAMED_PIPE 0x8000
-
-typedef struct smb_com_open_req { /* also handles create */
- struct smb_hdr hdr; /* wct = 24 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u8 Reserved; /* Must Be Zero */
- __le16 NameLength;
- __le32 OpenFlags;
- __u32 RootDirectoryFid;
- __le32 DesiredAccess;
- __le64 AllocationSize;
- __le32 FileAttributes;
- __le32 ShareAccess;
- __le32 CreateDisposition;
- __le32 CreateOptions;
- __le32 ImpersonationLevel;
- __u8 SecurityFlags;
- __le16 ByteCount;
- char fileName[];
-} __attribute__((packed)) OPEN_REQ;
-
-/* open response: oplock levels */
-#define OPLOCK_NONE 0
-#define OPLOCK_EXCLUSIVE 1
-#define OPLOCK_BATCH 2
-#define OPLOCK_READ 3 /* level 2 oplock */
-
-/* open response for CreateAction shifted left */
-#define CIFS_CREATE_ACTION 0x20000 /* file created */
-
-typedef struct smb_com_open_rsp {
- struct smb_hdr hdr; /* wct = 34 BB */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u8 OplockLevel;
- __u16 Fid;
- __le32 CreateAction;
- struct_group_attr(common_attributes, __packed,
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le32 FileAttributes;
- );
- __le64 AllocationSize;
- __le64 EndOfFile;
- __le16 FileType;
- __le16 DeviceState;
- __u8 DirectoryFlag;
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) OPEN_RSP;
-
-typedef struct smb_com_open_rsp_ext {
- struct smb_hdr hdr; /* wct = 42 but meaningless due to MS bug? */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u8 OplockLevel;
- __u16 Fid;
- __le32 CreateAction;
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le32 FileAttributes;
- __le64 AllocationSize;
- __le64 EndOfFile;
- __le16 FileType;
- __le16 DeviceState;
- __u8 DirectoryFlag;
- __u8 VolumeGUID[16];
- __u64 FileId; /* note no endian conversion - is opaque UniqueID */
- __le32 MaximalAccessRights;
- __le32 GuestMaximalAccessRights;
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) OPEN_RSP_EXT;
-
-
-/* format of legacy open request */
-typedef struct smb_com_openx_req {
- struct smb_hdr hdr; /* wct = 15 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 OpenFlags;
- __le16 Mode;
- __le16 Sattr; /* search attributes */
- __le16 FileAttributes; /* dos attrs */
- __le32 CreateTime; /* os2 format */
- __le16 OpenFunction;
- __le32 EndOfFile;
- __le32 Timeout;
- __le32 Reserved;
- __le16 ByteCount; /* file name follows */
- char fileName[];
-} __attribute__((packed)) OPENX_REQ;
-
-typedef struct smb_com_openx_rsp {
- struct smb_hdr hdr; /* wct = 15 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le16 FileAttributes;
- __le32 LastWriteTime; /* os2 format */
- __le32 EndOfFile;
- __le16 Access;
- __le16 FileType;
- __le16 IPCState;
- __le16 Action;
- __u32 FileId;
- __u16 Reserved;
- __u16 ByteCount;
-} __attribute__((packed)) OPENX_RSP;
-
-/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */
-
-/* Legacy write request for older servers */
-typedef struct smb_com_writex_req {
- struct smb_hdr hdr; /* wct = 12 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __u32 Reserved; /* Timeout */
- __le16 WriteMode; /* 1 = write through */
- __le16 Remaining;
- __le16 Reserved2;
- __le16 DataLengthLow;
- __le16 DataOffset;
- __le16 ByteCount;
- __u8 Pad; /* BB check for whether padded to DWORD
- boundary and optimum performance here */
- char Data[];
-} __attribute__((packed)) WRITEX_REQ;
-
-typedef struct smb_com_write_req {
- struct smb_hdr hdr; /* wct = 14 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __u32 Reserved;
- __le16 WriteMode;
- __le16 Remaining;
- __le16 DataLengthHigh;
- __le16 DataLengthLow;
- __le16 DataOffset;
- __le32 OffsetHigh;
- __le16 ByteCount;
- __u8 Pad; /* BB check for whether padded to DWORD
- boundary and optimum performance here */
- char Data[];
-} __attribute__((packed)) WRITE_REQ;
-
-typedef struct smb_com_write_rsp {
- struct smb_hdr hdr; /* wct = 6 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 Count;
- __le16 Remaining;
- __le16 CountHigh;
- __u16 Reserved;
- __u16 ByteCount;
-} __attribute__((packed)) WRITE_RSP;
-
-/* legacy read request for older servers */
-typedef struct smb_com_readx_req {
- struct smb_hdr hdr; /* wct = 10 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __le16 MaxCount;
- __le16 MinCount; /* obsolete */
- __le32 Reserved;
- __le16 Remaining;
- __le16 ByteCount;
-} __attribute__((packed)) READX_REQ;
-
-typedef struct smb_com_read_req {
- struct smb_hdr hdr; /* wct = 12 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __le16 MaxCount;
- __le16 MinCount; /* obsolete */
- __le32 MaxCountHigh;
- __le16 Remaining;
- __le32 OffsetHigh;
- __le16 ByteCount;
-} __attribute__((packed)) READ_REQ;
-
-typedef struct smb_com_read_rsp {
- struct smb_hdr hdr; /* wct = 12 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __le16 Remaining;
- __le16 DataCompactionMode;
- __le16 Reserved;
- __le16 DataLength;
- __le16 DataOffset;
- __le16 DataLengthHigh;
- __u64 Reserved2;
- __u16 ByteCount;
- /* read response data immediately follows */
-} __attribute__((packed)) READ_RSP;
-
-typedef struct locking_andx_range {
- __le16 Pid;
- __le16 Pad;
- __le32 OffsetHigh;
- __le32 OffsetLow;
- __le32 LengthHigh;
- __le32 LengthLow;
-} __attribute__((packed)) LOCKING_ANDX_RANGE;
-
-#define LOCKING_ANDX_SHARED_LOCK 0x01
-#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
-#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
-#define LOCKING_ANDX_CANCEL_LOCK 0x08
-#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */
-
-typedef struct smb_com_lock_req {
- struct smb_hdr hdr; /* wct = 8 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __u8 LockType;
- __u8 OplockLevel;
- __le32 Timeout;
- __le16 NumberOfUnlocks;
- __le16 NumberOfLocks;
- __le16 ByteCount;
- LOCKING_ANDX_RANGE Locks[];
-} __attribute__((packed)) LOCK_REQ;
-
-/* lock type */
-#define CIFS_RDLCK 0
-#define CIFS_WRLCK 1
-#define CIFS_UNLCK 2
-typedef struct cifs_posix_lock {
- __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */
- __le16 lock_flags; /* 1 = Wait (only valid for setlock) */
- __le32 pid;
- __le64 start;
- __le64 length;
- /* BB what about additional owner info to identify network client */
-} __attribute__((packed)) CIFS_POSIX_LOCK;
-
-typedef struct smb_com_lock_rsp {
- struct smb_hdr hdr; /* wct = 2 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 ByteCount;
-} __attribute__((packed)) LOCK_RSP;
-
-typedef struct smb_com_rename_req {
- struct smb_hdr hdr; /* wct = 1 */
- __le16 SearchAttributes; /* target file attributes */
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII or Unicode */
- unsigned char OldFileName[];
- /* followed by __u8 BufferFormat2 */
- /* followed by NewFileName */
-} __attribute__((packed)) RENAME_REQ;
-
- /* copy request flags */
-#define COPY_MUST_BE_FILE 0x0001
-#define COPY_MUST_BE_DIR 0x0002
-#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
-#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
-#define COPY_VERIFY_WRITES 0x0010
-#define COPY_TREE 0x0020
-
-typedef struct smb_com_copy_req {
- struct smb_hdr hdr; /* wct = 3 */
- __u16 Tid2;
- __le16 OpenFunction;
- __le16 Flags;
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII or Unicode */
- unsigned char OldFileName[];
- /* followed by __u8 BufferFormat2 */
- /* followed by NewFileName string */
-} __attribute__((packed)) COPY_REQ;
-
-typedef struct smb_com_copy_rsp {
- struct smb_hdr hdr; /* wct = 1 */
- __le16 CopyCount; /* number of files copied */
- __u16 ByteCount; /* may be zero */
- __u8 BufferFormat; /* 0x04 - only present if errored file follows */
- unsigned char ErrorFileName[]; /* only present if error in copy */
-} __attribute__((packed)) COPY_RSP;
-
-#define CREATE_HARD_LINK 0x103
-#define MOVEFILE_COPY_ALLOWED 0x0002
-#define MOVEFILE_REPLACE_EXISTING 0x0001
-
-typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
- struct smb_hdr hdr; /* wct = 4 */
- __le16 SearchAttributes; /* target file attributes */
- __le16 Flags; /* spec says Information Level */
- __le32 ClusterCount;
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII or Unicode */
- unsigned char OldFileName[];
- /* followed by __u8 BufferFormat2 */
- /* followed by NewFileName */
-} __attribute__((packed)) NT_RENAME_REQ;
-
-typedef struct smb_com_rename_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) RENAME_RSP;
-
-typedef struct smb_com_delete_file_req {
- struct smb_hdr hdr; /* wct = 1 */
- __le16 SearchAttributes;
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII */
- unsigned char fileName[];
-} __attribute__((packed)) DELETE_FILE_REQ;
-
-typedef struct smb_com_delete_file_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) DELETE_FILE_RSP;
-
-typedef struct smb_com_delete_directory_req {
- struct smb_hdr hdr; /* wct = 0 */
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII */
- unsigned char DirName[];
-} __attribute__((packed)) DELETE_DIRECTORY_REQ;
-
-typedef struct smb_com_delete_directory_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) DELETE_DIRECTORY_RSP;
-
-typedef struct smb_com_create_directory_req {
- struct smb_hdr hdr; /* wct = 0 */
- __le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII */
- unsigned char DirName[];
-} __attribute__((packed)) CREATE_DIRECTORY_REQ;
-
-typedef struct smb_com_create_directory_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) CREATE_DIRECTORY_RSP;
-
-typedef struct smb_com_query_information_req {
- struct smb_hdr hdr; /* wct = 0 */
- __le16 ByteCount; /* 1 + namelen + 1 */
- __u8 BufferFormat; /* 4 = ASCII */
- unsigned char FileName[];
-} __attribute__((packed)) QUERY_INFORMATION_REQ;
-
-typedef struct smb_com_query_information_rsp {
- struct smb_hdr hdr; /* wct = 10 */
- __le16 attr;
- __le32 last_write_time;
- __le32 size;
- __u16 reserved[5];
- __le16 ByteCount; /* bcc = 0 */
-} __attribute__((packed)) QUERY_INFORMATION_RSP;
-
-typedef struct smb_com_setattr_req {
- struct smb_hdr hdr; /* wct = 8 */
- __le16 attr;
- __le16 time_low;
- __le16 time_high;
- __le16 reserved[5]; /* must be zero */
- __u16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII */
- unsigned char fileName[];
-} __attribute__((packed)) SETATTR_REQ;
-
-typedef struct smb_com_setattr_rsp {
- struct smb_hdr hdr; /* wct = 0 */
- __u16 ByteCount; /* bct = 0 */
-} __attribute__((packed)) SETATTR_RSP;
-
-/* empty wct response to setattr */
-
-/*******************************************************/
-/* NT Transact structure definitions follow */
-/* Currently only ioctl, acl (get security descriptor) */
-/* and notify are implemented */
-/*******************************************************/
-typedef struct smb_com_ntransact_req {
- struct smb_hdr hdr; /* wct >= 19 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 2 = IOCTL/FSCTL */
- /* SetupCount words follow then */
- __le16 ByteCount;
- __u8 Pad[3];
- __u8 Parms[];
-} __attribute__((packed)) NTRANSACT_REQ;
-
-typedef struct smb_com_ntransact_rsp {
- struct smb_hdr hdr; /* wct = 18 */
- __u8 Reserved[3];
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 ParameterDisplacement;
- __le32 DataCount;
- __le32 DataOffset;
- __le32 DataDisplacement;
- __u8 SetupCount; /* 0 */
- __u16 ByteCount;
- /* __u8 Pad[3]; */
- /* parms and data follow */
-} __attribute__((packed)) NTRANSACT_RSP;
-
-/* See MS-SMB 2.2.7.2.1.1 */
-struct srv_copychunk {
- __le64 SourceOffset;
- __le64 DestinationOffset;
- __le32 CopyLength;
- __u32 Reserved;
-} __packed;
-
-typedef struct smb_com_transaction_ioctl_req {
- struct smb_hdr hdr; /* wct = 23 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 2 = IOCTL/FSCTL */
- __le32 FunctionCode;
- __u16 Fid;
- __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
- __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
- __le16 ByteCount;
- __u8 Pad[3];
- __u8 Data[];
-} __attribute__((packed)) TRANSACT_IOCTL_REQ;
-
-typedef struct smb_com_transaction_compr_ioctl_req {
- struct smb_hdr hdr; /* wct = 23 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 2 = IOCTL/FSCTL */
- __le32 FunctionCode;
- __u16 Fid;
- __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
- __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
- __le16 ByteCount;
- __u8 Pad[3];
- __le16 compression_state; /* See below for valid flags */
-} __attribute__((packed)) TRANSACT_COMPR_IOCTL_REQ;
-
-/* compression state flags */
-#define COMPRESSION_FORMAT_NONE 0x0000
-#define COMPRESSION_FORMAT_DEFAULT 0x0001
-#define COMPRESSION_FORMAT_LZNT1 0x0002
-
-typedef struct smb_com_transaction_ioctl_rsp {
- struct smb_hdr hdr; /* wct = 19 */
- __u8 Reserved[3];
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 ParameterDisplacement;
- __le32 DataCount;
- __le32 DataOffset;
- __le32 DataDisplacement;
- __u8 SetupCount; /* 1 */
- __le16 ReturnedDataLen;
- __le16 ByteCount;
-} __attribute__((packed)) TRANSACT_IOCTL_RSP;
-
-#define CIFS_ACL_OWNER 1
-#define CIFS_ACL_GROUP 2
-#define CIFS_ACL_DACL 4
-#define CIFS_ACL_SACL 8
-
-typedef struct smb_com_transaction_qsec_req {
- struct smb_hdr hdr; /* wct = 19 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* no setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 6 = QUERY_SECURITY_DESC */
- __le16 ByteCount; /* bcc = 3 + 8 */
- __u8 Pad[3];
- __u16 Fid;
- __u16 Reserved2;
- __le32 AclFlags;
-} __attribute__((packed)) QUERY_SEC_DESC_REQ;
-
-
-typedef struct smb_com_transaction_ssec_req {
- struct smb_hdr hdr; /* wct = 19 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* no setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 3 = SET_SECURITY_DESC */
- __le16 ByteCount; /* bcc = 3 + 8 */
- __u8 Pad[3];
- __u16 Fid;
- __u16 Reserved2;
- __le32 AclFlags;
-} __attribute__((packed)) SET_SEC_DESC_REQ;
-
-typedef struct smb_com_transaction_change_notify_req {
- struct smb_hdr hdr; /* wct = 23 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand;/* 4 = Change Notify */
- __le32 CompletionFilter; /* operation to monitor */
- __u16 Fid;
- __u8 WatchTree; /* 1 = Monitor subdirectories */
- __u8 Reserved2;
- __le16 ByteCount;
-/* __u8 Pad[3];*/
-/* __u8 Data[];*/
-} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
-
-/* BB eventually change to use generic ntransact rsp struct
- and validation routine */
-typedef struct smb_com_transaction_change_notify_rsp {
- struct smb_hdr hdr; /* wct = 18 */
- __u8 Reserved[3];
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 ParameterDisplacement;
- __le32 DataCount;
- __le32 DataOffset;
- __le32 DataDisplacement;
- __u8 SetupCount; /* 0 */
- __u16 ByteCount;
- /* __u8 Pad[3]; */
-} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP;
-/* Completion Filter flags for Notify */
-#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
-#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
-#define FILE_NOTIFY_CHANGE_NAME 0x00000003
-#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
-#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
-#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
-#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
-#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
-#define FILE_NOTIFY_CHANGE_EA 0x00000080
-#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
-#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
-#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
-#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
-
-#define FILE_ACTION_ADDED 0x00000001
-#define FILE_ACTION_REMOVED 0x00000002
-#define FILE_ACTION_MODIFIED 0x00000003
-#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
-#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
-#define FILE_ACTION_ADDED_STREAM 0x00000006
-#define FILE_ACTION_REMOVED_STREAM 0x00000007
-#define FILE_ACTION_MODIFIED_STREAM 0x00000008
-
-/* response contains array of the following structures */
-struct file_notify_information {
- __le32 NextEntryOffset;
- __le32 Action;
- __le32 FileNameLength;
- __u8 FileName[];
-} __attribute__((packed));
-
-struct cifs_quota_data {
- __u32 rsrvd1; /* 0 */
- __u32 sid_size;
- __u64 rsrvd2; /* 0 */
- __u64 space_used;
- __u64 soft_limit;
- __u64 hard_limit;
- char sid[]; /* variable size? */
-} __attribute__((packed));
-
-/* quota sub commands */
-#define QUOTA_LIST_CONTINUE 0
-#define QUOTA_LIST_START 0x100
-#define QUOTA_FOR_SID 0x101
-
-struct trans2_req {
- /* struct smb_hdr hdr precedes. Set wct = 14+ */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* 1st setup word - SetupCount words follow */
- __le16 ByteCount;
-} __attribute__((packed));
-
-struct smb_t2_req {
- struct smb_hdr hdr;
- struct trans2_req t2_req;
-} __attribute__((packed));
-
-struct trans2_resp {
- /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __u16 Reserved;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 ParameterDisplacement;
- __le16 DataCount;
- __le16 DataOffset;
- __le16 DataDisplacement;
- __u8 SetupCount;
- __u8 Reserved1;
- /* SetupWords[SetupCount];
- __u16 ByteCount;
- __u16 Reserved2;*/
- /* data area follows */
-} __attribute__((packed));
-
-struct smb_t2_rsp {
- struct smb_hdr hdr;
- struct trans2_resp t2_rsp;
-} __attribute__((packed));
-
-/* PathInfo/FileInfo infolevels */
-#define SMB_INFO_STANDARD 1
-#define SMB_SET_FILE_EA 2
-#define SMB_QUERY_FILE_EA_SIZE 2
-#define SMB_INFO_QUERY_EAS_FROM_LIST 3
-#define SMB_INFO_QUERY_ALL_EAS 4
-#define SMB_INFO_IS_NAME_VALID 6
-#define SMB_QUERY_FILE_BASIC_INFO 0x101
-#define SMB_QUERY_FILE_STANDARD_INFO 0x102
-#define SMB_QUERY_FILE_EA_INFO 0x103
-#define SMB_QUERY_FILE_NAME_INFO 0x104
-#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
-#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
-#define SMB_QUERY_FILE_ALL_INFO 0x107
-#define SMB_QUERY_ALT_NAME_INFO 0x108
-#define SMB_QUERY_FILE_STREAM_INFO 0x109
-#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
-#define SMB_QUERY_FILE_UNIX_BASIC 0x200
-#define SMB_QUERY_FILE_UNIX_LINK 0x201
-#define SMB_QUERY_POSIX_ACL 0x204
-#define SMB_QUERY_XATTR 0x205 /* e.g. system EA name space */
-#define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
-#define SMB_QUERY_POSIX_PERMISSION 0x207
-#define SMB_QUERY_POSIX_LOCK 0x208
-/* #define SMB_POSIX_OPEN 0x209 */
-/* #define SMB_POSIX_UNLINK 0x20a */
-#define SMB_QUERY_FILE__UNIX_INFO2 0x20b
-#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
-#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
-#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
-#define SMB_QUERY_FILE_POSITION_INFO 0x3f6
-#define SMB_QUERY_FILE_MODE_INFO 0x3f8
-#define SMB_QUERY_FILE_ALGN_INFO 0x3f9
-
-
-#define SMB_SET_FILE_BASIC_INFO 0x101
-#define SMB_SET_FILE_DISPOSITION_INFO 0x102
-#define SMB_SET_FILE_ALLOCATION_INFO 0x103
-#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
-#define SMB_SET_FILE_UNIX_BASIC 0x200
-#define SMB_SET_FILE_UNIX_LINK 0x201
-#define SMB_SET_FILE_UNIX_HLINK 0x203
-#define SMB_SET_POSIX_ACL 0x204
-#define SMB_SET_XATTR 0x205
-#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
-#define SMB_SET_POSIX_LOCK 0x208
-#define SMB_POSIX_OPEN 0x209
-#define SMB_POSIX_UNLINK 0x20a
-#define SMB_SET_FILE_UNIX_INFO2 0x20b
-#define SMB_SET_FILE_BASIC_INFO2 0x3ec
-#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
-#define SMB_FILE_ALL_INFO2 0x3fa
-#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
-#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
-#define SMB_FILE_MOVE_CLUSTER_INFO 0x407
-#define SMB_FILE_QUOTA_INFO 0x408
-#define SMB_FILE_REPARSEPOINT_INFO 0x409
-#define SMB_FILE_MAXIMUM_INFO 0x40d
-
-/* Find File infolevels */
-#define SMB_FIND_FILE_INFO_STANDARD 0x001
-#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002
-#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
-#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
-#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
-#define SMB_FIND_FILE_NAMES_INFO 0x103
-#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
-#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
-#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
-#define SMB_FIND_FILE_UNIX 0x202
-/* #define SMB_FIND_FILE_POSIX_INFO 0x064 */
-
-typedef struct smb_com_transaction2_qpi_req {
- struct smb_hdr hdr; /* wct = 14+ */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* one setup word */
- __le16 ByteCount;
- __u8 Pad;
- __le16 InformationLevel;
- __u32 Reserved4;
- char FileName[];
-} __attribute__((packed)) TRANSACTION2_QPI_REQ;
-
-typedef struct smb_com_transaction2_qpi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u16 Reserved2; /* parameter word is present for infolevels > 100 */
-} __attribute__((packed)) TRANSACTION2_QPI_RSP;
-
-typedef struct smb_com_transaction2_spi_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* one setup word */
- __le16 ByteCount;
- __u8 Pad;
- __u16 Pad1;
- __le16 InformationLevel;
- __u32 Reserved4;
- char FileName[];
-} __attribute__((packed)) TRANSACTION2_SPI_REQ;
-
-typedef struct smb_com_transaction2_spi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u16 Reserved2; /* parameter word is present for infolevels > 100 */
-} __attribute__((packed)) TRANSACTION2_SPI_RSP;
-
-struct set_file_rename {
- __le32 overwrite; /* 1 = overwrite dest */
- __u32 root_fid; /* zero */
- __le32 target_name_len;
- char target_name[]; /* Must be unicode */
-} __attribute__((packed));
-
-struct smb_com_transaction2_sfi_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* one setup word */
- __le16 ByteCount;
- __u8 Pad;
- __u16 Pad1;
- __u16 Fid;
- __le16 InformationLevel;
- __u16 Reserved4;
- __u8 payload[];
-} __attribute__((packed));
-
-struct smb_com_transaction2_sfi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
-} __attribute__((packed));
-
-struct smb_t2_qfi_req {
- struct smb_hdr hdr;
- struct trans2_req t2;
- __u8 Pad;
- __u16 Fid;
- __le16 InformationLevel;
-} __attribute__((packed));
-
-struct smb_t2_qfi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
-} __attribute__((packed));
-
-/*
- * Flags on T2 FINDFIRST and FINDNEXT
- */
-#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001
-#define CIFS_SEARCH_CLOSE_AT_END 0x0002
-#define CIFS_SEARCH_RETURN_RESUME 0x0004
-#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008
-#define CIFS_SEARCH_BACKUP_SEARCH 0x0010
-
-/*
- * Size of the resume key on FINDFIRST and FINDNEXT calls
- */
-#define CIFS_SMB_RESUME_KEY_SIZE 4
-
-typedef struct smb_com_transaction2_ffirst_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount; /* one */
- __u8 Reserved3;
- __le16 SubCommand; /* TRANS2_FIND_FIRST */
- __le16 ByteCount;
- __u8 Pad;
- __le16 SearchAttributes;
- __le16 SearchCount;
- __le16 SearchFlags;
- __le16 InformationLevel;
- __le32 SearchStorageType;
- char FileName[];
-} __attribute__((packed)) TRANSACTION2_FFIRST_REQ;
-
-typedef struct smb_com_transaction2_ffirst_rsp {
- struct smb_hdr hdr; /* wct = 10 */
- struct trans2_resp t2;
- __u16 ByteCount;
-} __attribute__((packed)) TRANSACTION2_FFIRST_RSP;
-
-typedef struct smb_com_transaction2_ffirst_rsp_parms {
- __u16 SearchHandle;
- __le16 SearchCount;
- __le16 EndofSearch;
- __le16 EAErrorOffset;
- __le16 LastNameOffset;
-} __attribute__((packed)) T2_FFIRST_RSP_PARMS;
-
-typedef struct smb_com_transaction2_fnext_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount; /* one */
- __u8 Reserved3;
- __le16 SubCommand; /* TRANS2_FIND_NEXT */
- __le16 ByteCount;
- __u8 Pad;
- __u16 SearchHandle;
- __le16 SearchCount;
- __le16 InformationLevel;
- __u32 ResumeKey;
- __le16 SearchFlags;
- char ResumeFileName[];
-} __attribute__((packed)) TRANSACTION2_FNEXT_REQ;
-
-typedef struct smb_com_transaction2_fnext_rsp {
- struct smb_hdr hdr; /* wct = 10 */
- struct trans2_resp t2;
- __u16 ByteCount;
-} __attribute__((packed)) TRANSACTION2_FNEXT_RSP;
-
-typedef struct smb_com_transaction2_fnext_rsp_parms {
- __le16 SearchCount;
- __le16 EndofSearch;
- __le16 EAErrorOffset;
- __le16 LastNameOffset;
-} __attribute__((packed)) T2_FNEXT_RSP_PARMS;
-
-/* QFSInfo Levels */
-#define SMB_INFO_ALLOCATION 1
-#define SMB_INFO_VOLUME 2
-#define SMB_QUERY_FS_VOLUME_INFO 0x102
-#define SMB_QUERY_FS_SIZE_INFO 0x103
-#define SMB_QUERY_FS_DEVICE_INFO 0x104
-#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
-#define SMB_QUERY_CIFS_UNIX_INFO 0x200
-#define SMB_QUERY_POSIX_FS_INFO 0x201
-#define SMB_QUERY_POSIX_WHO_AM_I 0x202
-#define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203
-#define SMB_QUERY_FS_PROXY 0x204 /* WAFS enabled. Returns structure
- FILE_SYSTEM__UNIX_INFO to tell
- whether new NTIOCTL available
- (0xACE) for WAN friendly SMB
- operations to be carried */
-#define SMB_QUERY_LABEL_INFO 0x3ea
-#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
-#define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef
-#define SMB_QUERY_OBJECTID_INFO 0x3f0
-
-typedef struct smb_com_transaction2_qfsi_req {
- struct smb_hdr hdr; /* wct = 14+ */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* one setup word */
- __le16 ByteCount;
- __u8 Pad;
- __le16 InformationLevel;
-} __attribute__((packed)) TRANSACTION2_QFSI_REQ;
-
-typedef struct smb_com_transaction_qfsi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u8 Pad; /* may be three bytes? *//* followed by data area */
-} __attribute__((packed)) TRANSACTION2_QFSI_RSP;
-
-typedef struct whoami_rsp_data { /* Query level 0x202 */
- __u32 flags; /* 0 = Authenticated user 1 = GUEST */
- __u32 mask; /* which flags bits server understands ie 0x0001 */
- __u64 unix_user_id;
- __u64 unix_user_gid;
- __u32 number_of_supplementary_gids; /* may be zero */
- __u32 number_of_sids; /* may be zero */
- __u32 length_of_sid_array; /* in bytes - may be zero */
- __u32 pad; /* reserved - MBZ */
- /* __u64 gid_array[0]; */ /* may be empty */
- /* __u8 * psid_list */ /* may be empty */
-} __attribute__((packed)) WHOAMI_RSP_DATA;
-
-/* SETFSInfo Levels */
-#define SMB_SET_CIFS_UNIX_INFO 0x200
-/* level 0x203 is defined above in list of QFS info levels */
-/* #define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 */
-
-/* Level 0x200 request structure follows */
-typedef struct smb_com_transaction2_setfsi_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount; /* 4 */
- __le16 ParameterOffset;
- __le16 DataCount; /* 12 */
- __le16 DataOffset;
- __u8 SetupCount; /* one */
- __u8 Reserved3;
- __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
- __le16 ByteCount;
- __u8 Pad;
- __u16 FileNum; /* Parameters start. */
- __le16 InformationLevel;/* Parameters end. */
- __le16 ClientUnixMajor; /* Data start. */
- __le16 ClientUnixMinor;
- __le64 ClientUnixCap; /* Data end */
-} __attribute__((packed)) TRANSACTION2_SETFSI_REQ;
-
-/* level 0x203 request structure follows */
-typedef struct smb_com_transaction2_setfs_enc_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount; /* 4 */
- __le16 ParameterOffset;
- __le16 DataCount; /* 12 */
- __le16 DataOffset;
- __u8 SetupCount; /* one */
- __u8 Reserved3;
- __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
- __le16 ByteCount;
- __u8 Pad;
- __u16 Reserved4; /* Parameters start. */
- __le16 InformationLevel;/* Parameters end. */
- /* NTLMSSP Blob, Data start. */
-} __attribute__((packed)) TRANSACTION2_SETFSI_ENC_REQ;
-
-/* response for setfsinfo levels 0x200 and 0x203 */
-typedef struct smb_com_transaction2_setfsi_rsp {
- struct smb_hdr hdr; /* wct = 10 */
- struct trans2_resp t2;
- __u16 ByteCount;
-} __attribute__((packed)) TRANSACTION2_SETFSI_RSP;
-
-typedef struct smb_com_transaction2_get_dfs_refer_req {
- struct smb_hdr hdr; /* wct = 15 */
- __le16 TotalParameterCount;
- __le16 TotalDataCount;
- __le16 MaxParameterCount;
- __le16 MaxDataCount;
- __u8 MaxSetupCount;
- __u8 Reserved;
- __le16 Flags;
- __le32 Timeout;
- __u16 Reserved2;
- __le16 ParameterCount;
- __le16 ParameterOffset;
- __le16 DataCount;
- __le16 DataOffset;
- __u8 SetupCount;
- __u8 Reserved3;
- __le16 SubCommand; /* one setup word */
- __le16 ByteCount;
- __u8 Pad[3]; /* Win2K has sent 0x0F01 (max response length
- perhaps?) followed by one byte pad - doesn't
- seem to matter though */
- __le16 MaxReferralLevel;
- char RequestFileName[];
-} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
-
-#define DFS_VERSION cpu_to_le16(0x0003)
-
-/* DFS server target type */
-#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
-#define DFS_TYPE_ROOT 0x0001
-
-/* Referral Entry Flags */
-#define DFS_NAME_LIST_REF 0x0200 /* set for domain or DC referral responses */
-#define DFS_TARGET_SET_BOUNDARY 0x0400 /* only valid with version 4 dfs req */
-
-typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
- __le16 VersionNumber; /* must be 3 or 4 */
- __le16 Size;
- __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
- __le16 ReferralEntryFlags;
- __le32 TimeToLive;
- __le16 DfsPathOffset;
- __le16 DfsAlternatePathOffset;
- __le16 NetworkAddressOffset; /* offset of the link target */
- __u8 ServiceSiteGuid[16]; /* MBZ, ignored */
-} __attribute__((packed)) REFERRAL3;
-
-struct get_dfs_referral_rsp {
- __le16 PathConsumed;
- __le16 NumberOfReferrals;
- __le32 DFSFlags;
- REFERRAL3 referrals[]; /* array of level 3 dfs_referral structures */
- /* followed by the strings pointed to by the referral structures */
-} __packed;
-
-typedef struct smb_com_transaction_get_dfs_refer_rsp {
- struct smb_hdr hdr; /* wct = 10 */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u8 Pad;
- struct get_dfs_referral_rsp dfs_data;
-} __packed TRANSACTION2_GET_DFS_REFER_RSP;
-
-/* DFS Flags */
-#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
-#define DFSREF_STORAGE_SERVER 0x00000002 /* no further ref requests needed */
-#define DFSREF_TARGET_FAILBACK 0x00000004 /* only for DFS referral version 4 */
-
-/*
- ************************************************************************
- * All structs for everything above the SMB PDUs themselves
- * (such as the T2 level specific data) go here
- ************************************************************************
- */
-
-/*
- * Information on a server
- */
-
-struct serverInfo {
- char name[16];
- unsigned char versionMajor;
- unsigned char versionMinor;
- unsigned long type;
- unsigned int commentOffset;
-} __attribute__((packed));
-
-/*
- * The following structure is the format of the data returned on a NetShareEnum
- * with level "90" (x5A)
- */
-
-struct shareInfo {
- char shareName[13];
- char pad;
- unsigned short type;
- unsigned int commentOffset;
-} __attribute__((packed));
-
-struct aliasInfo {
- char aliasName[9];
- char pad;
- unsigned int commentOffset;
- unsigned char type[2];
-} __attribute__((packed));
-
-struct aliasInfo92 {
- int aliasNameOffset;
- int serverNameOffset;
- int shareNameOffset;
-} __attribute__((packed));
-
-typedef struct {
- __le64 TotalAllocationUnits;
- __le64 FreeAllocationUnits;
- __le32 SectorsPerAllocationUnit;
- __le32 BytesPerSector;
-} __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */
-
-typedef struct {
- __le32 fsid;
- __le32 SectorsPerAllocationUnit;
- __le32 TotalAllocationUnits;
- __le32 FreeAllocationUnits;
- __le16 BytesPerSector;
-} __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO;
-
-typedef struct {
- __le16 MajorVersionNumber;
- __le16 MinorVersionNumber;
- __le64 Capability;
-} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
-
-/* Version numbers for CIFS UNIX major and minor. */
-#define CIFS_UNIX_MAJOR_VERSION 1
-#define CIFS_UNIX_MINOR_VERSION 0
-
-/* Linux/Unix extensions capability flags */
-#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
-#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */
-#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
-#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
-#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */
-#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
- calls including posix open
- and posix unlink */
-#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up to 0xFFFF00 */
-#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
-#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */
-#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */
-#define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and QFS PROXY call */
-#ifdef CONFIG_CIFS_POSIX
-/* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send
- LockingX instead of posix locking call on unix sess (and we do not expect
- LockingX to use different (ie Windows) semantics than posix locking on
- the same session (if WINE needs to do this later, we can add this cap
- back in later */
-/* #define CIFS_UNIX_CAP_MASK 0x000000fb */
-#define CIFS_UNIX_CAP_MASK 0x000003db
-#else
-#define CIFS_UNIX_CAP_MASK 0x00000013
-#endif /* CONFIG_CIFS_POSIX */
-
-
-#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
-
-typedef struct {
- /* For undefined recommended transfer size return -1 in that field */
- __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */
- __le32 BlockSize;
- /* The next three fields are in terms of the block size.
- (above). If block size is unknown, 4096 would be a
- reasonable block size for a server to report.
- Note that returning the blocks/blocksavail removes need
- to make a second call (to QFSInfo level 0x103 to get this info.
- UserBlockAvail is typically less than or equal to BlocksAvail,
- if no distinction is made return the same value in each */
- __le64 TotalBlocks;
- __le64 BlocksAvail; /* bfree */
- __le64 UserBlocksAvail; /* bavail */
- /* For undefined Node fields or FSID return -1 */
- __le64 TotalFileNodes;
- __le64 FreeFileNodes;
- __le64 FileSysIdentifier; /* fsid */
- /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */
- /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */
-} __attribute__((packed)) FILE_SYSTEM_POSIX_INFO;
-
-/* DeviceType Flags */
-#define FILE_DEVICE_CD_ROM 0x00000002
-#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
-#define FILE_DEVICE_DFS 0x00000006
-#define FILE_DEVICE_DISK 0x00000007
-#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
-#define FILE_DEVICE_FILE_SYSTEM 0x00000009
-#define FILE_DEVICE_NAMED_PIPE 0x00000011
-#define FILE_DEVICE_NETWORK 0x00000012
-#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
-#define FILE_DEVICE_NULL 0x00000015
-#define FILE_DEVICE_PARALLEL_PORT 0x00000016
-#define FILE_DEVICE_PRINTER 0x00000018
-#define FILE_DEVICE_SERIAL_PORT 0x0000001b
-#define FILE_DEVICE_STREAMS 0x0000001e
-#define FILE_DEVICE_TAPE 0x0000001f
-#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
-#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
-#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
-
-/* Device Characteristics */
-#define FILE_REMOVABLE_MEDIA 0x00000001
-#define FILE_READ_ONLY_DEVICE 0x00000002
-#define FILE_FLOPPY_DISKETTE 0x00000004
-#define FILE_WRITE_ONCE_MEDIA 0x00000008
-#define FILE_REMOTE_DEVICE 0x00000010
-#define FILE_DEVICE_IS_MOUNTED 0x00000020
-#define FILE_VIRTUAL_VOLUME 0x00000040
-#define FILE_DEVICE_SECURE_OPEN 0x00000100
-#define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000
-#define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000
-#define FILE_PORTABLE_DEVICE 0x00004000
-#define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000
-
-typedef struct {
- __le32 DeviceType;
- __le32 DeviceCharacteristics;
-} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
-
-/* minimum includes first three fields, and empty FS Name */
-#define MIN_FS_ATTR_INFO_SIZE 12
-
-
-/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */
-#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */
-#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */
-#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000
-#define FILE_SUPPORTS_USN_JOURNAL 0x02000000
-#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000
-#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000
-#define FILE_SUPPORTS_HARD_LINKS 0x00400000
-#define FILE_SUPPORTS_TRANSACTIONS 0x00200000
-#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
-#define FILE_READ_ONLY_VOLUME 0x00080000
-#define FILE_NAMED_STREAMS 0x00040000
-#define FILE_SUPPORTS_ENCRYPTION 0x00020000
-#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
-#define FILE_VOLUME_IS_COMPRESSED 0x00008000
-#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400
-#define FILE_RETURNS_CLEANUP_RESULT_INFO 0x00000200
-#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
-#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
-#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
-#define FILE_VOLUME_QUOTAS 0x00000020
-#define FILE_FILE_COMPRESSION 0x00000010
-#define FILE_PERSISTENT_ACLS 0x00000008
-#define FILE_UNICODE_ON_DISK 0x00000004
-#define FILE_CASE_PRESERVED_NAMES 0x00000002
-#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
-typedef struct {
- __le32 Attributes;
- __le32 MaxPathNameComponentLength;
- __le32 FileSystemNameLen;
- char FileSystemName[52]; /* do not have to save this - get subset? */
-} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
-
-/******************************************************************************/
-/* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
-/******************************************************************************/
-typedef struct { /* data block encoding of response to level 263 QPathInfo */
- struct_group_attr(common_attributes, __packed,
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le32 Attributes;
- );
- __u32 Pad1;
- __le64 AllocationSize;
- __le64 EndOfFile; /* size ie offset to first free byte in file */
- __le32 NumberOfLinks; /* hard links */
- __u8 DeletePending;
- __u8 Directory;
- __u16 Pad2;
- __le32 EASize;
- __le32 FileNameLength;
- union {
- char __pad;
- DECLARE_FLEX_ARRAY(char, FileName);
- };
-} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */
-
-typedef struct {
- __le64 AllocationSize;
- __le64 EndOfFile; /* size ie offset to first free byte in file */
- __le32 NumberOfLinks; /* hard links */
- __u8 DeletePending;
- __u8 Directory;
- __u16 Pad;
-} __attribute__((packed)) FILE_STANDARD_INFO; /* level 0x102 QPathInfo */
-
-
-/* defines for enumerating possible values of the Unix type field below */
-#define UNIX_FILE 0
-#define UNIX_DIR 1
-#define UNIX_SYMLINK 2
-#define UNIX_CHARDEV 3
-#define UNIX_BLOCKDEV 4
-#define UNIX_FIFO 5
-#define UNIX_SOCKET 6
-typedef struct {
- __le64 EndOfFile;
- __le64 NumOfBytes;
- __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
- __le64 LastAccessTime;
- __le64 LastModificationTime;
- __le64 Uid;
- __le64 Gid;
- __le32 Type;
- __le64 DevMajor;
- __le64 DevMinor;
- __le64 UniqueId;
- __le64 Permissions;
- __le64 Nlinks;
-} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */
-
-typedef struct {
- DECLARE_FLEX_ARRAY(char, LinkDest);
-} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */
-
-/* The following three structures are needed only for
- setting time to NT4 and some older servers via
- the primitive DOS time format */
-typedef struct {
- __u16 Day:5;
- __u16 Month:4;
- __u16 Year:7;
-} __attribute__((packed)) SMB_DATE;
-
-typedef struct {
- __u16 TwoSeconds:5;
- __u16 Minutes:6;
- __u16 Hours:5;
-} __attribute__((packed)) SMB_TIME;
-
-typedef struct {
- __le16 CreationDate; /* SMB Date see above */
- __le16 CreationTime; /* SMB Time */
- __le16 LastAccessDate;
- __le16 LastAccessTime;
- __le16 LastWriteDate;
- __le16 LastWriteTime;
- __le32 DataSize; /* File Size (EOF) */
- __le32 AllocationSize;
- __le16 Attributes; /* verify not u32 */
- __le32 EASize;
-} __attribute__((packed)) FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */
-
-typedef struct {
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le32 Attributes;
- __u32 Pad;
-} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */
-
-struct file_allocation_info {
- __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-} __packed; /* size used on disk, for level 0x103 for set, 0x105 for query */
-
-struct file_end_of_file_info {
- __le64 FileSize; /* offset to end of file */
-} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */
-
-struct file_alt_name_info {
- DECLARE_FLEX_ARRAY(__u8, alt_name);
-} __attribute__((packed)); /* level 0x0108 */
-
-struct file_stream_info {
- __le32 number_of_streams; /* BB check sizes and verify location */
- /* followed by info on streams themselves
- u64 size;
- u64 allocation_size
- stream info */
-}; /* level 0x109 */
-
-struct file_compression_info {
- __le64 compressed_size;
- __le16 format;
- __u8 unit_shift;
- __u8 ch_shift;
- __u8 cl_shift;
- __u8 pad[3];
-} __attribute__((packed)); /* level 0x10b */
-
-/* POSIX ACL set/query path info structures */
-#define CIFS_ACL_VERSION 1
-struct cifs_posix_ace { /* access control entry (ACE) */
- __u8 cifs_e_tag;
- __u8 cifs_e_perm;
- __le64 cifs_uid; /* or gid */
-} __attribute__((packed));
-
-struct cifs_posix_acl { /* access control list (ACL) */
- __le16 version;
- __le16 access_entry_count; /* access ACL - count of entries */
- __le16 default_entry_count; /* default ACL - count of entries */
- struct cifs_posix_ace ace_array[];
- /* followed by struct cifs_posix_ace default_ace_array[] */
-} __attribute__((packed)); /* level 0x204 */
-
-/* types of access control entries already defined in posix_acl.h */
-/* #define CIFS_POSIX_ACL_USER_OBJ 0x01
-#define CIFS_POSIX_ACL_USER 0x02
-#define CIFS_POSIX_ACL_GROUP_OBJ 0x04
-#define CIFS_POSIX_ACL_GROUP 0x08
-#define CIFS_POSIX_ACL_MASK 0x10
-#define CIFS_POSIX_ACL_OTHER 0x20 */
-
-/* types of perms */
-/* #define CIFS_POSIX_ACL_EXECUTE 0x01
-#define CIFS_POSIX_ACL_WRITE 0x02
-#define CIFS_POSIX_ACL_READ 0x04 */
-
-/* end of POSIX ACL definitions */
-
-/* POSIX Open Flags */
-#define SMB_O_RDONLY 0x1
-#define SMB_O_WRONLY 0x2
-#define SMB_O_RDWR 0x4
-#define SMB_O_CREAT 0x10
-#define SMB_O_EXCL 0x20
-#define SMB_O_TRUNC 0x40
-#define SMB_O_APPEND 0x80
-#define SMB_O_SYNC 0x100
-#define SMB_O_DIRECTORY 0x200
-#define SMB_O_NOFOLLOW 0x400
-#define SMB_O_DIRECT 0x800
-
-typedef struct {
- __le32 OpenFlags; /* same as NT CreateX */
- __le32 PosixOpenFlags;
- __le64 Permissions;
- __le16 Level; /* reply level requested (see QPathInfo levels) */
-} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
-
-typedef struct {
- __le16 OplockFlags;
- __u16 Fid;
- __le32 CreateAction;
- __le16 ReturnedLevel;
- __le16 Pad;
- /* struct following varies based on requested level */
-} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
-
-#define SMB_POSIX_UNLINK_FILE_TARGET 0
-#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
-
-struct unlink_psx_rq { /* level 0x20a SetPathInfo */
- __le16 type;
-} __attribute__((packed));
-
-struct file_internal_info {
- __le64 UniqueId; /* inode number */
-} __attribute__((packed)); /* level 0x3ee */
-
-struct file_mode_info {
- __le32 Mode;
-} __attribute__((packed)); /* level 0x3f8 */
-
-struct file_attrib_tag {
- __le32 Attribute;
- __le32 ReparseTag;
-} __attribute__((packed)); /* level 0x40b */
-
-
-/********************************************************/
-/* FindFirst/FindNext transact2 data buffer formats */
-/********************************************************/
-
-typedef struct {
- __le32 NextEntryOffset;
- __u32 ResumeKey; /* as with FileIndex - no need to convert */
- FILE_UNIX_BASIC_INFO basic;
- union {
- char __pad;
- DECLARE_FLEX_ARRAY(char, FileName);
- };
-} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
-
-typedef struct {
- __le32 NextEntryOffset;
- __u32 FileIndex;
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le64 EndOfFile;
- __le64 AllocationSize;
- __le32 ExtFileAttributes;
- __le32 FileNameLength;
- char FileName[];
-} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */
-
-typedef struct {
- __le32 NextEntryOffset;
- __u32 FileIndex;
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le64 EndOfFile;
- __le64 AllocationSize;
- __le32 ExtFileAttributes;
- __le32 FileNameLength;
- __le32 EaSize; /* length of the xattrs */
- char FileName[];
-} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
-
-typedef struct {
- __le32 NextEntryOffset;
- __u32 FileIndex;
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le64 EndOfFile;
- __le64 AllocationSize;
- __le32 ExtFileAttributes;
- __le32 FileNameLength;
- __le32 EaSize; /* EA size */
- __le32 Reserved;
- __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
- char FileName[];
-} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
-
-typedef struct {
- __le32 NextEntryOffset;
- __u32 FileIndex;
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le64 EndOfFile;
- __le64 AllocationSize;
- __le32 ExtFileAttributes;
- __le32 FileNameLength;
- __le32 EaSize; /* length of the xattrs */
- __u8 ShortNameLength;
- __u8 Reserved;
- __u8 ShortName[24];
- char FileName[];
-} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
-
-typedef struct {
- __u32 ResumeKey;
- __le16 CreationDate; /* SMB Date */
- __le16 CreationTime; /* SMB Time */
- __le16 LastAccessDate;
- __le16 LastAccessTime;
- __le16 LastWriteDate;
- __le16 LastWriteTime;
- __le32 DataSize; /* File Size (EOF) */
- __le32 AllocationSize;
- __le16 Attributes; /* verify not u32 */
- __u8 FileNameLength;
- char FileName[];
-} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
-
-
-struct fea {
- unsigned char EA_flags;
- __u8 name_len;
- __le16 value_len;
- char name[];
- /* optionally followed by value */
-} __attribute__((packed));
-/* flags for _FEA.fEA */
-#define FEA_NEEDEA 0x80 /* need EA bit */
-
-struct fealist {
- __le32 list_len;
- struct fea list;
-} __attribute__((packed));
-
-/* used to hold an arbitrary blob of data */
-struct data_blob {
- __u8 *data;
- size_t length;
- void (*free) (struct data_blob *data_blob);
-} __attribute__((packed));
-
-
-#ifdef CONFIG_CIFS_POSIX
-/*
- For better POSIX semantics from Linux client, (even better
- than the existing CIFS Unix Extensions) we need updated PDUs for:
-
- 1) PosixCreateX - to set and return the mode, inode#, device info and
- perhaps add a CreateDevice - to create Pipes and other special .inodes
- Also note POSIX open flags
- 2) Close - to return the last write time to do cache across close
- more safely
- 3) FindFirst return unique inode number - what about resume key, two
- forms short (matches readdir) and full (enough info to cache inodes)
- 4) Mkdir - set mode
-
- And under consideration:
- 5) FindClose2 (return nanosecond timestamp ??)
- 6) Use nanosecond timestamps throughout all time fields if
- corresponding attribute flag is set
- 7) sendfile - handle based copy
-
- what about fixing 64 bit alignment
-
- There are also various legacy SMB/CIFS requests used as is
-
- From existing Lanman and NTLM dialects:
- --------------------------------------
- NEGOTIATE
- SESSION_SETUP_ANDX (BB which?)
- TREE_CONNECT_ANDX (BB which wct?)
- TREE_DISCONNECT (BB add volume timestamp on response)
- LOGOFF_ANDX
- DELETE (note delete open file behavior)
- DELETE_DIRECTORY
- READ_AND_X
- WRITE_AND_X
- LOCKING_AND_X (note posix lock semantics)
- RENAME (note rename across dirs and open file rename posix behaviors)
- NT_RENAME (for hardlinks) Is this good enough for all features?
- FIND_CLOSE2
- TRANSACTION2 (18 cases)
- SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
- (BB verify that never need to set allocation size)
- SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via
- Unix ext?)
-
- COPY (note support for copy across directories) - FUTURE, OPTIONAL
- setting/getting OS/2 EAs - FUTURE (BB can this handle
- setting Linux xattrs perfectly) - OPTIONAL
- dnotify - FUTURE, OPTIONAL
- quota - FUTURE, OPTIONAL
-
- Note that various requests implemented for NT interop such as
- NT_TRANSACT (IOCTL) QueryReparseInfo
- are unneeded to servers compliant with the CIFS POSIX extensions
-
- From CIFS Unix Extensions:
- -------------------------
- T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
- T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
- T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
- T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) BB check for missing
- inode fields
- Actually a need QUERY_FILE_UNIX_INFO
- since has inode num
- BB what about a) blksize/blkbits/blocks
- b) i_version
- c) i_rdev
- d) notify mask?
- e) generation
- f) size_seqcount
- T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
- TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
- T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
- */
-
-/* xsymlink is a symlink format (used by MacOS) that can be used
- to save symlink info in a regular file when
- mounted to operating systems that do not
- support the cifs Unix extensions or EAs (for xattr
- based symlinks). For such a file to be recognized
- as containing symlink data:
-
- 1) file size must be 1067,
- 2) signature must begin file data,
- 3) length field must be set to ASCII representation
- of a number which is less than or equal to 1024,
- 4) md5 must match that of the path data */
-
-struct xsymlink {
- /* 1067 bytes */
- char signature[4]; /* XSym */ /* not null terminated */
- char cr0; /* \n */
-/* ASCII representation of length (4 bytes decimal) terminated by \n not null */
- char length[4];
- char cr1; /* \n */
-/* md5 of valid subset of path ie path[0] through path[length-1] */
- __u8 md5[32];
- char cr2; /* \n */
-/* if room left, then end with \n then 0x20s by convention but not required */
- char path[1024];
-} __attribute__((packed));
-
-typedef struct file_xattr_info {
- /* BB do we need another field for flags? BB */
- __u32 xattr_name_len;
- __u32 xattr_value_len;
- char xattr_name[];
- /* followed by xattr_value[xattr_value_len], no pad */
-} __packed FILE_XATTR_INFO; /* extended attribute info level 0x205 */
-
-/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
-
-typedef struct file_chattr_info {
- __le64 mask; /* list of all possible attribute bits */
- __le64 mode; /* list of actual attribute bits on this inode */
-} __packed FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */
-#endif /* POSIX */
-#endif /* _CIFSPDU_H */
+#endif /* _CIFSPDU_H */
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 59f6fdfe560e..4a25afda9448 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -9,10 +9,12 @@
#define _CIFSPROTO_H
#include <linux/nls.h>
#include <linux/ctype.h>
+#include "cifsglob.h"
#include "trace.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h"
#endif
+#include "smb1proto.h"
struct statfs;
struct smb_rqst;
@@ -24,18 +26,15 @@ struct smb3_fs_context;
*****************************************************************
*/
-extern struct smb_hdr *cifs_buf_get(void);
-extern void cifs_buf_release(void *);
-extern struct smb_hdr *cifs_small_buf_get(void);
-extern void cifs_small_buf_release(void *);
-extern void free_rsp_buf(int, void *);
-extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
- unsigned int /* length */);
-extern int smb_send_kvec(struct TCP_Server_Info *server,
- struct msghdr *msg,
- size_t *sent);
-extern unsigned int _get_xid(void);
-extern void _free_xid(unsigned int);
+void *cifs_buf_get(void);
+void cifs_buf_release(void *buf_to_free);
+void *cifs_small_buf_get(void);
+void cifs_small_buf_release(void *buf_to_free);
+void free_rsp_buf(int resp_buftype, void *rsp);
+int smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+ size_t *sent);
+unsigned int _get_xid(void);
+void _free_xid(unsigned int xid);
#define get_xid() \
({ \
unsigned int __xid = _get_xid(); \
@@ -56,16 +55,16 @@ do { \
else \
trace_smb3_exit_done(curr_xid, __func__); \
} while (0)
-extern int init_cifs_idmap(void);
-extern void exit_cifs_idmap(void);
-extern int init_cifs_spnego(void);
-extern void exit_cifs_spnego(void);
-extern const char *build_path_from_dentry(struct dentry *, void *);
-char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
- const char *tree, int tree_len,
- bool prefix);
-extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
- void *page, bool prefix);
+int init_cifs_idmap(void);
+void exit_cifs_idmap(void);
+int init_cifs_spnego(void);
+void exit_cifs_spnego(void);
+const char *build_path_from_dentry(struct dentry *direntry, void *page);
+char *__build_path_from_dentry_optional_prefix(struct dentry *direntry,
+ void *page, const char *tree,
+ int tree_len, bool prefix);
+char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
+ void *page, bool prefix);
static inline void *alloc_dentry_path(void)
{
return __getname();
@@ -77,526 +76,267 @@ static inline void free_dentry_path(void *page)
__putname(page);
}
-extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
- struct cifs_sb_info *cifs_sb,
- struct cifs_tcon *tcon,
- int add_treename);
-extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
+char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
+ struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, int add_treename);
char *cifs_build_devname(char *nodename, const char *prepath);
-extern void delete_mid(struct mid_q_entry *mid);
-void __release_mid(struct kref *refcount);
-extern void cifs_wake_up_task(struct mid_q_entry *mid);
-extern int cifs_handle_standard(struct TCP_Server_Info *server,
- struct mid_q_entry *mid);
-extern char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx,
- char dirsep);
-extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
-extern int smb3_parse_opt(const char *options, const char *key, char **val);
-extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
-extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
-extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
-extern int cifs_call_async(struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- mid_receive_t *receive, mid_callback_t *callback,
- mid_handle_t *handle, void *cbdata, const int flags,
- const struct cifs_credits *exist_credits);
-extern struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
-extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst, int *resp_buf_type,
- const int flags, struct kvec *resp_iov);
-extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const int flags, const int num_rqst,
- struct smb_rqst *rqst, int *resp_buf_type,
- struct kvec *resp_iov);
-extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
- struct smb_hdr * /* input */ ,
- struct smb_hdr * /* out */ ,
- int * /* bytes returned */ , const int);
-extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
- char *in_buf, int flags);
-extern struct mid_q_entry *cifs_setup_request(struct cifs_ses *,
- struct TCP_Server_Info *,
- struct smb_rqst *);
-extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
- struct smb_rqst *);
-extern int cifs_check_receive(struct mid_q_entry *mid,
- struct TCP_Server_Info *server, bool log_error);
-extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
- size_t size, size_t *num,
- struct cifs_credits *credits);
-extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
- struct kvec *, int /* nvec to send */,
- int * /* type of buf returned */, const int flags,
- struct kvec * /* resp vec */);
-extern int SendReceiveBlockingLock(const unsigned int xid,
- struct cifs_tcon *ptcon,
- struct smb_hdr *in_buf,
- struct smb_hdr *out_buf,
- int *bytes_returned);
-
-void
-cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
- bool all_channels);
-void
-cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
- bool mark_smb_session);
-extern int cifs_reconnect(struct TCP_Server_Info *server,
- bool mark_smb_session);
-extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
-extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
-extern bool backup_cred(struct cifs_sb_info *);
-extern bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 eof,
- bool from_readdir);
-extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
- unsigned int bytes_written);
-void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result,
- bool was_async);
-extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
-extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
- int flags,
- struct cifsFileInfo **ret_file);
-extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
- int flags,
- struct cifsFileInfo **ret_file);
-extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
- struct cifsFileInfo **ret_file);
-extern int cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode,
- struct file *file);
-extern unsigned int smbCalcSize(void *buf);
-extern int decode_negTokenInit(unsigned char *security_blob, int length,
+void delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid);
+void __release_mid(struct TCP_Server_Info *server,
+ struct mid_q_entry *midEntry);
+void cifs_wake_up_task(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid);
+int cifs_handle_standard(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid);
+char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep);
+int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
+int smb3_parse_opt(const char *options, const char *key, char **val);
+int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
+bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
+int cifs_discard_remaining_data(struct TCP_Server_Info *server);
+int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+ mid_receive_t receive, mid_callback_t callback,
+ mid_handle_t handle, void *cbdata, const int flags,
+ const struct cifs_credits *exist_credits);
+struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
+int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server, struct smb_rqst *rqst,
+ int *resp_buf_type, const int flags, struct kvec *resp_iov);
+int compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server, const int flags,
+ const int num_rqst, struct smb_rqst *rqst,
+ int *resp_buf_type, struct kvec *resp_iov);
+int cifs_sync_mid_result(struct mid_q_entry *mid,
+ struct TCP_Server_Info *server);
+int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
+ struct smb_rqst *rqst);
+int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
+ unsigned int *instance);
+int cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
+ size_t *num, struct cifs_credits *credits);
+
+static inline int
+send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, struct mid_q_entry *mid,
+ unsigned int xid)
+{
+ return server->ops->send_cancel ?
+ server->ops->send_cancel(ses, server, rqst, mid, xid) : 0;
+}
+
+int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *mid);
+
+void smb2_query_server_interfaces(struct work_struct *work);
+void cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
+ bool all_channels);
+void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
+ bool mark_smb_session);
+int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session);
+bool backup_cred(struct cifs_sb_info *cifs_sb);
+bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
+ bool from_readdir);
+void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata,
+ ssize_t result);
+struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
+ int flags);
+int __cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
+ unsigned int find_flags, unsigned int open_flags,
+ struct cifsFileInfo **ret_file);
+int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+ struct inode *inode, int flags,
+ struct cifsFileInfo **ret_file);
+struct cifsFileInfo *__find_readable_file(struct cifsInodeInfo *cifs_inode,
+ unsigned int find_flags,
+ unsigned int open_flags);
+int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+ struct cifsFileInfo **ret_file);
+int cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode,
+ struct file *file);
+int decode_negTokenInit(unsigned char *security_blob, int length,
struct TCP_Server_Info *server);
-extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
-extern void cifs_set_port(struct sockaddr *addr, const unsigned short int port);
-extern int map_smb_to_linux_error(char *buf, bool logErr);
-extern int map_and_check_smb_error(struct mid_q_entry *mid, bool logErr);
-extern void header_assemble(struct smb_hdr *, char /* command */ ,
- const struct cifs_tcon *, int /* length of
- fixed section (word count) in two byte units */);
-extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
- struct cifs_ses *ses,
- void **request_buf);
-extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
- enum securityEnum requested);
-extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const struct nls_table *nls_cp);
-extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
-extern u64 cifs_UnixTimeToNT(struct timespec64);
-extern struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
- int offset);
-extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
-extern int cifs_get_writer(struct cifsInodeInfo *cinode);
-extern void cifs_put_writer(struct cifsInodeInfo *cinode);
-extern void cifs_done_oplock_break(struct cifsInodeInfo *cinode);
-extern int cifs_unlock_range(struct cifsFileInfo *cfile,
- struct file_lock *flock, const unsigned int xid);
-extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
-
-extern void cifs_down_write(struct rw_semaphore *sem);
+int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
+void cifs_set_port(struct sockaddr *addr, const unsigned short int port);
+struct timespec64 cifs_NTtimeToUnix(__le64 ntutc);
+u64 cifs_UnixTimeToNT(struct timespec64 t);
+struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset);
+void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
+int cifs_get_writer(struct cifsInodeInfo *cinode);
+void cifs_put_writer(struct cifsInodeInfo *cinode);
+void cifs_done_oplock_break(struct cifsInodeInfo *cinode);
+int cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
+ unsigned int xid);
+int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
+
+void cifs_down_write(struct rw_semaphore *sem);
struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct tcon_link *tlink, __u32 oplock,
const char *symlink_target);
-extern int cifs_posix_open(const char *full_path, struct inode **inode,
- struct super_block *sb, int mode,
- unsigned int f_flags, __u32 *oplock, __u16 *netfid,
- unsigned int xid);
+int cifs_posix_open(const char *full_path, struct inode **pinode,
+ struct super_block *sb, int mode, unsigned int f_flags,
+ __u32 *poplock, __u16 *pnetfid, unsigned int xid);
void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
-extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
- FILE_UNIX_BASIC_INFO *info,
- struct cifs_sb_info *cifs_sb);
-extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *,
- struct cifs_sb_info *);
-extern int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
- bool from_readdir);
-extern struct inode *cifs_iget(struct super_block *sb,
- struct cifs_fattr *fattr);
+void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
+ FILE_UNIX_BASIC_INFO *info,
+ struct cifs_sb_info *cifs_sb);
+void cifs_dir_info_to_fattr(struct cifs_fattr *fattr,
+ FILE_DIRECTORY_INFO *info,
+ struct cifs_sb_info *cifs_sb);
+int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
+ bool from_readdir);
+struct inode *cifs_iget(struct super_block *sb, struct cifs_fattr *fattr);
int cifs_get_inode_info(struct inode **inode, const char *full_path,
- struct cifs_open_info_data *data, struct super_block *sb, int xid,
+ struct cifs_open_info_data *data,
+ struct super_block *sb, int xid,
const struct cifs_fid *fid);
-extern int smb311_posix_get_inode_info(struct inode **inode,
- const char *full_path,
- struct cifs_open_info_data *data,
- struct super_block *sb,
- const unsigned int xid);
-extern int cifs_get_inode_info_unix(struct inode **pinode,
- const unsigned char *search_path,
- struct super_block *sb, unsigned int xid);
-extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
- unsigned int xid, const char *full_path, __u32 dosattr);
-extern int cifs_rename_pending_delete(const char *full_path,
- struct dentry *dentry,
- const unsigned int xid);
-extern int sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
- struct cifs_fattr *fattr, uint sidtype);
-extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
- struct cifs_fattr *fattr, struct inode *inode,
- bool get_mode_from_special_sid,
- const char *path, const struct cifs_fid *pfid);
-extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
- kuid_t uid, kgid_t gid);
-extern struct smb_ntsd *get_cifs_acl(struct cifs_sb_info *cifssmb, struct inode *ino,
- const char *path, u32 *plen, u32 info);
-extern struct smb_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifssb,
- const struct cifs_fid *pfid, u32 *plen, u32 info);
-extern struct posix_acl *cifs_get_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, int type);
-extern int cifs_set_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, struct posix_acl *acl, int type);
-extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino,
- const char *path, int flag);
-extern unsigned int setup_authusers_ACE(struct smb_ace *pace);
-extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
- bool posix,
- __u64 nmode);
-extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
-
-extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
-extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
- unsigned int to_read);
-extern ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server,
- size_t to_read);
+int smb311_posix_get_inode_info(struct inode **inode, const char *full_path,
+ struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid);
+int cifs_get_inode_info_unix(struct inode **pinode,
+ const unsigned char *full_path,
+ struct super_block *sb, unsigned int xid);
+int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+ unsigned int xid, const char *full_path, __u32 dosattr);
+int cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+ const unsigned int xid);
+int sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
+ struct cifs_fattr *fattr, uint sidtype);
+int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+ struct inode *inode, bool mode_from_special_sid,
+ const char *path, const struct cifs_fid *pfid);
+int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
+ kuid_t uid, kgid_t gid);
+struct smb_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
+ struct inode *inode, const char *path,
+ u32 *pacllen, u32 info);
+struct smb_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
+ const struct cifs_fid *cifsfid,
+ u32 *pacllen, u32 info);
+struct posix_acl *cifs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ int type);
+int cifs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct posix_acl *acl, int type);
+int set_cifs_acl(struct smb_ntsd *pnntsd, __u32 acllen, struct inode *inode,
+ const char *path, int aclflag);
+unsigned int setup_authusers_ACE(struct smb_ace *pntace);
+unsigned int setup_special_mode_ACE(struct smb_ace *pntace, bool posix,
+ __u64 nmode);
+unsigned int setup_special_user_owner_ACE(struct smb_ace *pntace);
+
+void dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid,
+ bool malformed);
+int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
+ unsigned int to_read);
+ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server,
+ size_t to_read);
int cifs_read_iter_from_socket(struct TCP_Server_Info *server,
- struct iov_iter *iter,
- unsigned int to_read);
-extern int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb);
+ struct iov_iter *iter, unsigned int to_read);
+int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb);
void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx);
int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx);
int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx);
int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx);
-extern int cifs_match_super(struct super_block *, void *);
-extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx);
-extern void cifs_umount(struct cifs_sb_info *);
-extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
-extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
-
-extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
- __u64 length, __u8 type, __u16 flags,
- struct cifsLockInfo **conf_lock,
- int rw_check);
-extern void cifs_add_pending_open(struct cifs_fid *fid,
+int cifs_match_super(struct super_block *sb, void *data);
+int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx);
+void cifs_umount(struct cifs_sb_info *cifs_sb);
+void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
+void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
+
+bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
+ __u64 length, __u8 type, __u16 flags,
+ struct cifsLockInfo **conf_lock, int rw_check);
+void cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
+ struct cifs_pending_open *open);
+void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink,
struct cifs_pending_open *open);
-extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
- struct tcon_link *tlink,
- struct cifs_pending_open *open);
-extern void cifs_del_pending_open(struct cifs_pending_open *open);
+void cifs_del_pending_open(struct cifs_pending_open *open);
-extern bool cifs_is_deferred_close(struct cifsFileInfo *cfile,
- struct cifs_deferred_close **dclose);
+bool cifs_is_deferred_close(struct cifsFileInfo *cfile,
+ struct cifs_deferred_close **pdclose);
-extern void cifs_add_deferred_close(struct cifsFileInfo *cfile,
- struct cifs_deferred_close *dclose);
+void cifs_add_deferred_close(struct cifsFileInfo *cfile,
+ struct cifs_deferred_close *dclose);
-extern void cifs_del_deferred_close(struct cifsFileInfo *cfile);
+void cifs_del_deferred_close(struct cifsFileInfo *cfile);
-extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
+void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
-extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
+void cifs_close_all_deferred_files(struct cifs_tcon *tcon);
-extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
- const char *path);
+void cifs_close_all_deferred_files_sb(struct cifs_sb_info *cifs_sb);
+void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
+ struct dentry *dentry);
-extern void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
- const char *path);
+void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
+ const char *path);
-extern struct TCP_Server_Info *
-cifs_get_tcp_session(struct smb3_fs_context *ctx,
- struct TCP_Server_Info *primary_server);
-extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
- int from_reconnect);
-extern void cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);
+struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx,
+ struct TCP_Server_Info *primary_server);
+void cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect);
+void cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);
-extern void cifs_release_automount_timer(void);
+void cifs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);
-extern void cifs_move_llist(struct list_head *source, struct list_head *dest);
-extern void cifs_free_llist(struct list_head *llist);
-extern void cifs_del_lock_waiters(struct cifsLockInfo *lock);
+void cifs_move_llist(struct list_head *source, struct list_head *dest);
+void cifs_free_llist(struct list_head *llist);
+void cifs_del_lock_waiters(struct cifsLockInfo *lock);
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon);
-extern int cifs_negotiate_protocol(const unsigned int xid,
- struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- struct nls_table *nls_info);
-extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
-extern int CIFSSMBNegotiate(const unsigned int xid,
- struct cifs_ses *ses,
+int cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server);
-
-extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
- const char *tree, struct cifs_tcon *tcon,
- const struct nls_table *);
-
-extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
- const char *searchName, struct cifs_sb_info *cifs_sb,
- __u16 *searchHandle, __u16 search_flags,
- struct cifs_search_info *psrch_inf,
- bool msearch);
-
-extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
- __u16 searchHandle, __u16 search_flags,
- struct cifs_search_info *psrch_inf);
-
-extern int CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
- const __u16 search_handle);
-
-extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
- u16 netfid, FILE_ALL_INFO *pFindData);
-extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
- const char *search_Name, FILE_ALL_INFO *data,
- int legacy /* whether to use old info level */,
- const struct nls_table *nls_codepage, int remap);
-extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
- const char *search_name, FILE_ALL_INFO *data,
- const struct nls_table *nls_codepage, int remap);
-
-extern int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
- u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
-extern int CIFSSMBUnixQPathInfo(const unsigned int xid,
- struct cifs_tcon *tcon,
- const unsigned char *searchName,
- FILE_UNIX_BASIC_INFO *pFindData,
- const struct nls_table *nls_codepage, int remap);
-
-extern int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
- const char *search_name,
- struct dfs_info3_param **target_nodes,
- unsigned int *num_of_nodes,
- const struct nls_table *nls_codepage, int remap);
-
-extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
- unsigned int *num_of_nodes,
- struct dfs_info3_param **target_nodes,
- const struct nls_table *nls_codepage, int remap,
- const char *searchName, bool is_unicode);
-extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb,
- struct smb3_fs_context *ctx);
-extern int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
- struct kstatfs *FSData);
-extern int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
- struct kstatfs *FSData);
-extern int CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon,
- __u64 cap);
-
-extern int CIFSSMBQFSAttributeInfo(const unsigned int xid,
- struct cifs_tcon *tcon);
-extern int CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon);
-extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
-extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
- struct kstatfs *FSData);
-
-extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, const FILE_BASIC_INFO *data,
- const struct nls_table *nls_codepage,
- struct cifs_sb_info *cifs_sb);
-extern int CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
- const FILE_BASIC_INFO *data, __u16 fid,
- __u32 pid_of_opener);
-extern int CIFSSMBSetFileDisposition(const unsigned int xid,
- struct cifs_tcon *tcon,
- bool delete_file, __u16 fid,
- __u32 pid_of_opener);
-extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
- const char *file_name, __u64 size,
- struct cifs_sb_info *cifs_sb, bool set_allocation,
- struct dentry *dentry);
-extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifsFileInfo *cfile, __u64 size,
- bool set_allocation);
-
-struct cifs_unix_set_info_args {
- __u64 ctime;
- __u64 atime;
- __u64 mtime;
- __u64 mode;
- kuid_t uid;
- kgid_t gid;
- dev_t device;
-};
-
-extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
- struct cifs_tcon *tcon,
- const struct cifs_unix_set_info_args *args,
- u16 fid, u32 pid_of_opener);
-
-extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
- struct cifs_tcon *tcon, const char *file_name,
- const struct cifs_unix_set_info_args *args,
- const struct nls_table *nls_codepage,
- int remap);
-
-extern int CIFSSMBMkDir(const unsigned int xid, struct inode *inode,
- umode_t mode, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb);
-extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb);
-extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, __u16 type,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
-extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb,
- struct dentry *dentry);
-int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
- struct dentry *source_dentry,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb);
-extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
- int netfid, const char *target_name,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
-int CIFSCreateHardLink(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct dentry *source_dentry,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb);
-extern int CIFSUnixCreateHardLink(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
-extern int CIFSUnixCreateSymLink(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap);
-extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
- struct cifs_tcon *tcon,
- const unsigned char *searchName, char **syminfo,
- const struct nls_table *nls_codepage, int remap);
-extern int cifs_query_reparse_point(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb,
- const char *full_path,
- u32 *tag, struct kvec *rsp,
- int *rsp_buftype);
-extern int CIFSSMB_set_compression(const unsigned int xid,
- struct cifs_tcon *tcon, __u16 fid);
-extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
- int *oplock, FILE_ALL_INFO *buf);
-extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, const int disposition,
- const int access_flags, const int omode,
- __u16 *netfid, int *pOplock, FILE_ALL_INFO *,
- const struct nls_table *nls_codepage, int remap);
-extern int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
- u32 posix_flags, __u64 mode, __u16 *netfid,
- FILE_UNIX_BASIC_INFO *pRetData,
- __u32 *pOplock, const char *name,
- const struct nls_table *nls_codepage, int remap);
-extern int CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon,
- const int smb_file_id);
-
-extern int CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon,
- const int smb_file_id);
-
-extern int CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, char **buf,
- int *return_buf_type);
-extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, const char *buf);
-extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, struct kvec *iov, const int nvec);
-extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
- const char *search_name, __u64 *inode_number,
- const struct nls_table *nls_codepage,
- int remap);
-
-extern int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
- const __u16 netfid, const __u8 lock_type,
- const __u32 num_unlock, const __u32 num_lock,
- LOCKING_ANDX_RANGE *buf);
-extern int CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
- const __u16 netfid, const __u32 netpid, const __u64 len,
- const __u64 offset, const __u32 numUnlock,
- const __u32 numLock, const __u8 lockType,
- const bool waitFlag, const __u8 oplock_level);
-extern int CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
- const __u16 smb_file_id, const __u32 netpid,
- const loff_t start_offset, const __u64 len,
- struct file_lock *, const __u16 lock_type,
- const bool waitFlag);
-extern int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon);
-extern int CIFSSMBEcho(struct TCP_Server_Info *server);
-extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
-
-extern struct cifs_ses *sesInfoAlloc(void);
-extern void sesInfoFree(struct cifs_ses *);
-extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled,
- enum smb3_tcon_ref_trace trace);
-extern void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);
-
-extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
- __u32 *pexpected_response_sequence_number);
-extern int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
- __u32 *);
-extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
-extern int cifs_verify_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server,
- __u32 expected_sequence_number);
-extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
-extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
-extern int calc_seckey(struct cifs_ses *);
-extern int generate_smb30signingkey(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-extern int generate_smb311signingkey(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
+int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ struct nls_table *nls_info);
+int cifs_enable_signing(struct TCP_Server_Info *server,
+ bool mnt_sign_required);
+
+int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
+ unsigned int *num_of_nodes,
+ struct dfs_info3_param **target_nodes,
+ const struct nls_table *nls_codepage, int remap,
+ const char *searchName, bool is_unicode);
+
+struct cifs_ses *sesInfoAlloc(void);
+void sesInfoFree(struct cifs_ses *buf_to_free);
+struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled,
+ enum smb3_tcon_ref_trace trace);
+void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);
+
+int setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp);
+void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
+int calc_seckey(struct cifs_ses *ses);
+int generate_smb30signingkey(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+int generate_smb311signingkey(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *searchName,
- const unsigned char *ea_name, char *EAData,
- size_t bufsize, struct cifs_sb_info *cifs_sb);
-extern int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, const char *ea_name,
- const void *ea_value, const __u16 ea_value_len,
- const struct nls_table *nls_codepage,
- struct cifs_sb_info *cifs_sb);
-extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
- __u16 fid, struct smb_ntsd **acl_inf, __u32 *buflen, __u32 info);
-extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
- struct smb_ntsd *pntsd, __u32 len, int aclflag);
-extern int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *searchName,
- struct posix_acl **acl, const int acl_type,
- const struct nls_table *nls_codepage, int remap);
-extern int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *fileName,
- const struct posix_acl *acl, const int acl_type,
- const struct nls_table *nls_codepage, int remap);
-extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
- const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
-#endif /* CIFS_ALLOW_INSECURE_LEGACY */
-extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
-extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
-extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb,
- struct cifs_fattr *fattr,
- const unsigned char *path);
-extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
- const struct nls_table *codepage);
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
+bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
+int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+ const unsigned char *path);
+int E_md4hash(const unsigned char *passwd, unsigned char *p16,
+ const struct nls_table *codepage);
+
+struct TCP_Server_Info *cifs_find_tcp_session(struct smb3_fs_context *ctx);
-extern struct TCP_Server_Info *
-cifs_find_tcp_session(struct smb3_fs_context *ctx);
+struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
void __cifs_put_smb_ses(struct cifs_ses *ses);
-extern struct cifs_ses *
-cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);
+struct cifs_ses *cifs_get_smb_ses(struct TCP_Server_Info *server,
+ struct smb3_fs_context *ctx);
-int cifs_async_readv(struct cifs_io_subrequest *rdata);
-int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
+int cifs_readv_receive(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid);
-void cifs_async_writev(struct cifs_io_subrequest *wdata);
int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
@@ -606,45 +346,37 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server, char *signature,
- struct shash_desc *shash);
-enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
- enum securityEnum);
-
-int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
-void cifs_free_hash(struct shash_desc **sdesc);
+ struct TCP_Server_Info *server, char *signature,
+ struct cifs_calc_sig_ctx *ctx);
+enum securityEnum cifs_select_sectype(struct TCP_Server_Info *server,
+ enum securityEnum requested);
int cifs_try_adding_channels(struct cifs_ses *ses);
+int smb3_update_ses_channels(struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ bool from_reconnect, bool disable_mchan);
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
-void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
-int
-cifs_ses_get_chan_index(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-void
-cifs_chan_set_in_reconnect(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-void
-cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
+int cifs_ses_get_chan_index(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+void cifs_chan_set_in_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+void cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+void cifs_chan_set_need_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+void cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+bool cifs_chan_needs_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server);
-void
-cifs_chan_set_need_reconnect(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-void
-cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
+bool cifs_chan_is_iface_active(struct cifs_ses *ses,
struct TCP_Server_Info *server);
-bool
-cifs_chan_needs_reconnect(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-bool
-cifs_chan_is_iface_active(struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-void
-cifs_disable_secondary_channels(struct cifs_ses *ses);
-void
-cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
-int
-SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_mount);
+void cifs_decrease_secondary_channels(struct cifs_ses *ses,
+ bool disable_mchan);
+void cifs_chan_update_iface(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+int SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon,
+ bool in_mount);
void extract_unc_hostname(const char *unc, const char **h, size_t *len);
int copy_path_name(char *dst, const char *src);
@@ -657,9 +389,8 @@ void cifs_put_tcp_super(struct super_block *sb);
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
char *extract_hostname(const char *unc);
char *extract_sharename(const char *unc);
-int parse_reparse_point(struct reparse_data_buffer *buf,
- u32 plen, struct cifs_sb_info *cifs_sb,
- const char *full_path,
+int parse_reparse_point(struct reparse_data_buffer *buf, u32 plen,
+ struct cifs_sb_info *cifs_sb, const char *full_path,
struct cifs_open_info_data *data);
int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
@@ -680,14 +411,12 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
referral, NULL);
}
-int match_target_ip(struct TCP_Server_Info *server,
- const char *host, size_t hostlen,
- bool *result);
+int match_target_ip(struct TCP_Server_Info *server, const char *host,
+ size_t hostlen, bool *result);
int cifs_inval_name_dfs_link_error(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
- const char *full_path,
- bool *islink);
+ const char *full_path, bool *islink);
#else
static inline int cifs_inval_name_dfs_link_error(const unsigned int xid,
struct cifs_tcon *tcon,
@@ -743,9 +472,15 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
return true;
}
-static inline void release_mid(struct mid_q_entry *mid)
+static inline void smb_get_mid(struct mid_q_entry *mid)
{
- kref_put(&mid->refcount, __release_mid);
+ refcount_inc(&mid->refcount);
+}
+
+static inline void release_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+ if (refcount_dec_and_test(&mid->refcount))
+ __release_mid(server, mid);
}
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
@@ -755,4 +490,126 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
memset(data, 0, sizeof(*data));
}
+static inline int smb_EIO(enum smb_eio_trace trace)
+{
+ trace_smb3_eio(trace, 0, 0);
+ return -EIO;
+}
+
+static inline int smb_EIO1(enum smb_eio_trace trace, unsigned long info)
+{
+ trace_smb3_eio(trace, info, 0);
+ return -EIO;
+}
+
+static inline int smb_EIO2(enum smb_eio_trace trace, unsigned long info, unsigned long info2)
+{
+ trace_smb3_eio(trace, info, info2);
+ return -EIO;
+}
+
+static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
+ int num_rqst,
+ const u8 *sig)
+{
+ unsigned int len, skip;
+ unsigned int nents = 0;
+ unsigned long addr;
+ size_t data_size;
+ int i, j;
+
+ /*
+ * The first rqst has a transform header where the first 20 bytes are
+ * not part of the encrypted blob.
+ */
+ skip = 20;
+
+ /* Assumes the first rqst has a transform header as the first iov.
+ * I.e.
+ * rqst[0].rq_iov[0] is transform header
+ * rqst[0].rq_iov[1+] data to be encrypted/decrypted
+ * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
+ */
+ for (i = 0; i < num_rqst; i++) {
+ data_size = iov_iter_count(&rqst[i].rq_iter);
+
+ /* We really don't want a mixture of pinned and unpinned pages
+ * in the sglist. It's hard to keep track of which is what.
+ * Instead, we convert to a BVEC-type iterator higher up.
+ */
+ if (data_size &&
+ WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
+ return smb_EIO(smb_eio_trace_user_iter);
+
+ /* We also don't want to have any extra refs or pins to clean
+ * up in the sglist.
+ */
+ if (data_size &&
+ WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
+ return smb_EIO(smb_eio_trace_extract_will_pin);
+
+ for (j = 0; j < rqst[i].rq_nvec; j++) {
+ struct kvec *iov = &rqst[i].rq_iov[j];
+
+ addr = (unsigned long)iov->iov_base + skip;
+ if (is_vmalloc_or_module_addr((void *)addr)) {
+ len = iov->iov_len - skip;
+ nents += DIV_ROUND_UP(offset_in_page(addr) + len,
+ PAGE_SIZE);
+ } else {
+ nents++;
+ }
+ skip = 0;
+ }
+ if (data_size)
+ nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
+ }
+ nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
+ return nents;
+}
+
+/* We can not use the normal sg_set_buf() as we will sometimes pass a
+ * stack object as buf.
+ */
+static inline void cifs_sg_set_buf(struct sg_table *sgtable,
+ const void *buf,
+ unsigned int buflen)
+{
+ unsigned long addr = (unsigned long)buf;
+ unsigned int off = offset_in_page(addr);
+
+ addr &= PAGE_MASK;
+ if (is_vmalloc_or_module_addr((void *)addr)) {
+ do {
+ unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
+
+ sg_set_page(&sgtable->sgl[sgtable->nents++],
+ vmalloc_to_page((void *)addr), len, off);
+
+ off = 0;
+ addr += PAGE_SIZE;
+ buflen -= len;
+ } while (buflen);
+ } else {
+ sg_set_page(&sgtable->sgl[sgtable->nents++],
+ virt_to_page((void *)addr), buflen, off);
+ }
+}
+
+static inline int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
+ unsigned int find_flags,
+ struct cifsFileInfo **ret_file)
+{
+ find_flags &= ~FIND_OPEN_FLAGS;
+ return __cifs_get_writable_file(cifs_inode, find_flags, 0, ret_file);
+}
+
+static inline struct cifsFileInfo *
+find_readable_file(struct cifsInodeInfo *cinode, unsigned int find_flags)
+{
+ find_flags &= ~FIND_OPEN_FLAGS;
+ find_flags |= FIND_NO_PENDING_DELETE;
+ return __find_readable_file(cinode, find_flags, 0);
+}
+
#endif /* _CIFSPROTO_H */
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 60cb264a01e5..3990a9012264 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -26,11 +26,12 @@
#include <linux/uaccess.h>
#include <linux/netfs.h>
#include <trace/events/netfs.h>
-#include "cifspdu.h"
-#include "cifsfs.h"
#include "cifsglob.h"
-#include "cifsacl.h"
#include "cifsproto.h"
+#include "smb1proto.h"
+#include "../common/smbfsctl.h"
+#include "cifsfs.h"
+#include "cifsacl.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "fscache.h"
@@ -226,6 +227,7 @@ static int
small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
void **request_buf)
{
+ unsigned int in_len;
int rc;
rc = cifs_reconnect_tcon(tcon, smb_command);
@@ -238,13 +240,13 @@ small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
return -ENOMEM;
}
- header_assemble((struct smb_hdr *) *request_buf, smb_command,
- tcon, wct);
+ in_len = header_assemble((struct smb_hdr *) *request_buf, smb_command,
+ tcon, wct);
if (tcon != NULL)
cifs_stats_inc(&tcon->num_smbs_sent);
- return 0;
+ return in_len;
}
int
@@ -255,7 +257,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
struct smb_hdr *buffer;
rc = small_smb_init(smb_command, wct, NULL, request_buf);
- if (rc)
+ if (rc < 0)
return rc;
buffer = (struct smb_hdr *)*request_buf;
@@ -278,6 +280,8 @@ static int
__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
void **request_buf, void **response_buf)
{
+ unsigned int in_len;
+
*request_buf = cifs_buf_get();
if (*request_buf == NULL) {
/* BB should we add a retry in here if not a writepage? */
@@ -290,13 +294,13 @@ __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
if (response_buf)
*response_buf = *request_buf;
- header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
- wct);
+ in_len = header_assemble((struct smb_hdr *)*request_buf, smb_command, tcon,
+ wct);
if (tcon != NULL)
cifs_stats_inc(&tcon->num_smbs_sent);
- return 0;
+ return in_len;
}
/* If the return code is zero, this function must fill in request_buf pointer */
@@ -361,7 +365,7 @@ vt2_err:
}
static int
-decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
+decode_ext_sec_blob(struct cifs_ses *ses, SMB_NEGOTIATE_RSP *pSMBr)
{
int rc = 0;
u16 count;
@@ -370,7 +374,8 @@ decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
count = get_bcc(&pSMBr->hdr);
if (count < SMB1_CLIENT_GUID_SIZE)
- return -EIO;
+ return smb_EIO2(smb_eio_trace_neg_sec_blob_too_small,
+ count, SMB1_CLIENT_GUID_SIZE);
spin_lock(&cifs_tcp_ses_lock);
if (server->srv_count > 1) {
@@ -419,8 +424,9 @@ CIFSSMBNegotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
- NEGOTIATE_REQ *pSMB;
- NEGOTIATE_RSP *pSMBr;
+ SMB_NEGOTIATE_REQ *pSMB;
+ SMB_NEGOTIATE_RSP *pSMBr;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int i;
@@ -428,13 +434,14 @@ CIFSSMBNegotiate(const unsigned int xid,
if (!server) {
WARN(1, "%s: server is NULL!\n", __func__);
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
}
rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
(void **) &pSMB, (void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Mid = get_next_mid(server);
pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
@@ -458,10 +465,10 @@ CIFSSMBNegotiate(const unsigned int xid,
memcpy(&pSMB->DialectsArray[count], protocols[i].name, len);
count += len;
}
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc != 0)
goto neg_err_exit;
@@ -498,6 +505,7 @@ CIFSSMBNegotiate(const unsigned int xid,
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+ server->session_key_id = pSMBr->SessionKey;
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
server->timeAdj *= 60;
@@ -510,7 +518,8 @@ CIFSSMBNegotiate(const unsigned int xid,
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
rc = decode_ext_sec_blob(ses, pSMBr);
} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
- rc = -EIO; /* no crypt key only if plain text pwd */
+ /* no crypt key only if plain text pwd */
+ rc = smb_EIO(smb_eio_trace_neg_no_crypt_key);
} else {
server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
server->capabilities &= ~CAP_EXTENDED_SECURITY;
@@ -525,17 +534,158 @@ neg_err_exit:
return rc;
}
+/*
+ * Issue a TREE_CONNECT request.
+ */
+int
+CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
+ const char *tree, struct cifs_tcon *tcon,
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ TCONX_REQ *pSMB;
+ TCONX_RSP *pSMBr;
+ unsigned char *bcc_ptr;
+ int rc = 0;
+ int length, in_len;
+ __u16 bytes_left, count;
+
+ if (ses == NULL)
+ return smb_EIO(smb_eio_trace_null_pointers);
+
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == NULL)
+ return -ENOMEM;
+
+ smb_buffer_response = smb_buffer;
+
+ in_len = header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
+ NULL /*no tid */, 4 /*wct */);
+
+ smb_buffer->Mid = get_next_mid(ses->server);
+ smb_buffer->Uid = ses->Suid;
+ pSMB = (TCONX_REQ *) smb_buffer;
+ pSMBr = (TCONX_RSP *) smb_buffer_response;
+
+ pSMB->AndXCommand = 0xFF;
+ pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
+ bcc_ptr = &pSMB->Password[0];
+
+ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
+ *bcc_ptr = 0; /* password is null byte */
+ bcc_ptr++; /* skip password */
+ /* already aligned so no need to do it below */
+
+ if (ses->server->sign)
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ if (ses->capabilities & CAP_STATUS32)
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+ if (ses->capabilities & CAP_DFS)
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ length =
+ cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
+ 6 /* max utf8 char length in bytes */ *
+ (/* server len*/ + 256 /* share len */), nls_codepage);
+ bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
+ bcc_ptr += 2; /* skip trailing null */
+ } else { /* ASCII */
+ strcpy(bcc_ptr, tree);
+ bcc_ptr += strlen(tree) + 1;
+ }
+ strcpy(bcc_ptr, "?????");
+ bcc_ptr += strlen("?????");
+ bcc_ptr += 1;
+ count = bcc_ptr - &pSMB->Password[0];
+ in_len += count;
+ pSMB->ByteCount = cpu_to_le16(count);
+
+ rc = SendReceive(xid, ses, smb_buffer, in_len, smb_buffer_response,
+ &length, 0);
+
+ /* above now done in SendReceive */
+ if (rc == 0) {
+ bool is_unicode;
+
+ tcon->tid = smb_buffer_response->Tid;
+ bcc_ptr = pByteArea(smb_buffer_response);
+ bytes_left = get_bcc(smb_buffer_response);
+ length = strnlen(bcc_ptr, bytes_left - 2);
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
+ is_unicode = true;
+ else
+ is_unicode = false;
+
+
+ /* skip service field (NB: this field is always ASCII) */
+ if (length == 3) {
+ if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
+ (bcc_ptr[2] == 'C')) {
+ cifs_dbg(FYI, "IPC connection\n");
+ tcon->ipc = true;
+ tcon->pipe = true;
+ }
+ } else if (length == 2) {
+ if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
+ /* the most common case */
+ cifs_dbg(FYI, "disk share connection\n");
+ }
+ }
+ bcc_ptr += length + 1;
+ bytes_left -= (length + 1);
+ strscpy(tcon->tree_name, tree, sizeof(tcon->tree_name));
+
+ /* mostly informational -- no need to fail on error here */
+ kfree(tcon->nativeFileSystem);
+ tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
+ bytes_left, is_unicode,
+ nls_codepage);
+
+ cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
+
+ if ((smb_buffer_response->WordCount == 3) ||
+ (smb_buffer_response->WordCount == 7))
+ /* field is in same location */
+ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+ else
+ tcon->Flags = 0;
+ cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
+
+ /*
+ * reset_cifs_unix_caps calls QFSInfo which requires
+ * need_reconnect to be false, but we would not need to call
+ * reset_caps if this were not a reconnect case so must check
+ * need_reconnect flag here. The caller will also clear
+ * need_reconnect when tcon was successful but needed to be
+ * cleared earlier in the case of unix extensions reconnect
+ */
+ if (tcon->need_reconnect && tcon->unix_ext) {
+ cifs_dbg(FYI, "resetting caps for %s\n", tcon->tree_name);
+ tcon->need_reconnect = false;
+ reset_cifs_unix_caps(xid, tcon, NULL, NULL);
+ }
+ }
+ cifs_buf_release(smb_buffer);
+ return rc;
+}
+
int
CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
{
struct smb_hdr *smb_buffer;
+ unsigned int in_len;
int rc = 0;
cifs_dbg(FYI, "In tree disconnect\n");
/* BB: do we need to check this? These should never be NULL. */
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
/*
* No need to return error on this operation if tid invalidated and
@@ -546,16 +696,17 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
spin_lock(&tcon->ses->chan_lock);
if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) {
spin_unlock(&tcon->ses->chan_lock);
- return -EIO;
+ return smb_EIO(smb_eio_trace_tdis_in_reconnect);
}
spin_unlock(&tcon->ses->chan_lock);
rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
(void **)&smb_buffer);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, in_len, 0);
cifs_small_buf_release(smb_buffer);
if (rc)
cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
@@ -576,12 +727,11 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
* FIXME: maybe we should consider checking that the reply matches request?
*/
static void
-cifs_echo_callback(struct mid_q_entry *mid)
+cifs_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- struct TCP_Server_Info *server = mid->callback_data;
struct cifs_credits credits = { .value = 1, .instance = 0 };
- release_mid(mid);
+ release_mid(server, mid);
add_credits(server, &credits, CIFS_ECHO_OP);
}
@@ -590,15 +740,19 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
{
ECHO_REQ *smb;
int rc = 0;
- struct kvec iov[2];
- struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = 2 };
+ struct kvec iov[1];
+ struct smb_rqst rqst = {
+ .rq_iov = iov,
+ .rq_nvec = ARRAY_SIZE(iov),
+ };
+ unsigned int in_len;
cifs_dbg(FYI, "In echo request\n");
rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (server->capabilities & CAP_UNICODE)
smb->hdr.Flags2 |= SMBFLG2_UNICODE;
@@ -609,12 +763,10 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
put_unaligned_le16(1, &smb->EchoCount);
put_bcc(1, &smb->hdr);
smb->Data[0] = 'a';
- inc_rfc1001_len(smb, 3);
+ in_len += 3;
- iov[0].iov_len = 4;
+ iov[0].iov_len = in_len;
iov[0].iov_base = smb;
- iov[1].iov_len = get_rfc1002_length(smb);
- iov[1].iov_base = (char *)smb + 4;
rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
@@ -630,6 +782,7 @@ int
CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
{
LOGOFF_ANDX_REQ *pSMB;
+ unsigned int in_len;
int rc = 0;
cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
@@ -640,7 +793,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
* should probably be a BUG()
*/
if (!ses || !ses->server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
mutex_lock(&ses->session_mutex);
spin_lock(&ses->chan_lock);
@@ -652,10 +805,11 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
spin_unlock(&ses->chan_lock);
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
- if (rc) {
+ if (rc < 0) {
mutex_unlock(&ses->session_mutex);
return rc;
}
+ in_len = rc;
pSMB->hdr.Mid = get_next_mid(ses->server);
@@ -665,7 +819,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
pSMB->hdr.Uid = ses->Suid;
pSMB->AndXCommand = 0xFF;
- rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
session_already_dead:
mutex_unlock(&ses->session_mutex);
@@ -686,6 +840,7 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
struct unlink_psx_rq *pRqD;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -695,8 +850,9 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
PsxDelete:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -717,14 +873,11 @@ PsxDelete:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- /* Setup pointer to Request Data (inode type).
- * Note that SMB offsets are from the beginning of SMB which is 4 bytes
- * in, after RFC1001 field
- */
- pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
+ /* Setup pointer to Request Data (inode type). */
+ pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset);
pRqD->type = cpu_to_le16(type);
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
@@ -739,9 +892,9 @@ PsxDelete:
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "Posix delete returned %d\n", rc);
@@ -761,6 +914,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{
DELETE_FILE_REQ *pSMB = NULL;
DELETE_FILE_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -769,8 +923,9 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
DelFileRetry:
rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
@@ -784,9 +939,9 @@ DelFileRetry:
pSMB->SearchAttributes =
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
pSMB->BufferFormat = 0x04;
- inc_rfc1001_len(pSMB, name_len + 1);
+ in_len += name_len + 1;
pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
if (rc)
@@ -805,6 +960,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{
DELETE_DIRECTORY_REQ *pSMB = NULL;
DELETE_DIRECTORY_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -814,8 +970,9 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
RmDirRetry:
rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
@@ -828,9 +985,9 @@ RmDirRetry:
}
pSMB->BufferFormat = 0x04;
- inc_rfc1001_len(pSMB, name_len + 1);
+ in_len += name_len + 1;
pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
if (rc)
@@ -850,6 +1007,7 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
int rc = 0;
CREATE_DIRECTORY_REQ *pSMB = NULL;
CREATE_DIRECTORY_RSP *pSMBr = NULL;
+ unsigned int in_len;
int bytes_returned;
int name_len;
int remap = cifs_remap(cifs_sb);
@@ -858,8 +1016,9 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
MkDirRetry:
rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
@@ -872,9 +1031,9 @@ MkDirRetry:
}
pSMB->BufferFormat = 0x04;
- inc_rfc1001_len(pSMB, name_len + 1);
+ in_len += name_len + 1;
pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
if (rc)
@@ -895,6 +1054,7 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -906,8 +1066,9 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
PsxCreat:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -929,10 +1090,9 @@ PsxCreat:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
+ pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset);
pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
pdata->Permissions = cpu_to_le64(mode);
pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
@@ -950,9 +1110,9 @@ PsxCreat:
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Posix create returned %d\n", rc);
@@ -963,13 +1123,14 @@ PsxCreat:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_create_rsp_too_small,
+ get_bcc(&pSMBr->hdr), sizeof(OPEN_PSX_RSP));
goto psx_create_err;
}
/* copy return information to pRetData */
- psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
- + le16_to_cpu(pSMBr->t2.DataOffset));
+ psx_rsp = (OPEN_PSX_RSP *)
+ ((char *)pSMBr + le16_to_cpu(pSMBr->t2.DataOffset));
*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
if (netfid)
@@ -989,9 +1150,9 @@ PsxCreat:
pRetData->Type = cpu_to_le32(-1);
goto psx_create_err;
}
- memcpy((char *) pRetData,
- (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
- sizeof(FILE_UNIX_BASIC_INFO));
+ memcpy(pRetData,
+ (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
+ sizeof(*pRetData));
}
psx_create_err:
@@ -1078,6 +1239,7 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
OPENX_REQ *pSMB = NULL;
OPENX_RSP *pSMBr = NULL;
+ unsigned int in_len;
int bytes_returned;
int name_len;
__u16 count;
@@ -1085,8 +1247,9 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
OldOpenRetry:
rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->AndXCommand = 0xFF; /* none */
@@ -1129,10 +1292,10 @@ OldOpenRetry:
pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
count += name_len;
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
if (rc) {
@@ -1162,7 +1325,7 @@ OldOpenRetry:
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
pfile_info->EndOfFile = pfile_info->AllocationSize;
pfile_info->NumberOfLinks = cpu_to_le32(1);
- pfile_info->DeletePending = 0;
+ pfile_info->DeletePending = 0; /* successful open = not delete pending */
}
}
@@ -1190,12 +1353,14 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
int desired_access = oparms->desired_access;
int disposition = oparms->disposition;
const char *path = oparms->path;
+ unsigned int in_len;
openRetry:
rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
(void **)&rsp);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
/* no commands go after this */
req->AndXCommand = 0xFF;
@@ -1253,10 +1418,10 @@ openRetry:
req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
count += name_len;
- inc_rfc1001_len(req, count);
+ in_len += count;
req->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, in_len,
(struct smb_hdr *)rsp, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
if (rc) {
@@ -1287,7 +1452,7 @@ openRetry:
buf->AllocationSize = rsp->AllocationSize;
buf->EndOfFile = rsp->EndOfFile;
buf->NumberOfLinks = cpu_to_le32(1);
- buf->DeletePending = 0;
+ buf->DeletePending = 0; /* successful open = not delete pending */
}
cifs_buf_release(req);
@@ -1295,14 +1460,13 @@ openRetry:
}
static void
-cifs_readv_callback(struct mid_q_entry *mid)
+cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
struct cifs_io_subrequest *rdata = mid->callback_data;
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
- struct TCP_Server_Info *server = tcon->ses->server;
struct smb_rqst rqst = { .rq_iov = rdata->iov,
- .rq_nvec = 2,
+ .rq_nvec = 1,
.rq_iter = rdata->subreq.io_iter };
struct cifs_credits credits = {
.value = 1,
@@ -1310,6 +1474,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
.rreq_debug_id = rdata->rreq->debug_id,
.rreq_debug_index = rdata->subreq.debug_index,
};
+ unsigned int rreq_debug_id = rdata->rreq->debug_id;
+ unsigned int subreq_debug_index = rdata->subreq.debug_index;
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
__func__, mid->mid, mid->mid_state, rdata->result,
@@ -1333,7 +1499,12 @@ cifs_readv_callback(struct mid_q_entry *mid)
cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
case MID_REQUEST_SUBMITTED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted);
+ goto do_retry;
case MID_RETRY_NEEDED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
+do_retry:
+ __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
rdata->result = -EAGAIN;
if (server->sign && rdata->got_bytes)
/* reset bytes number since we can not check a sign */
@@ -1342,17 +1513,32 @@ cifs_readv_callback(struct mid_q_entry *mid)
task_io_account_read(rdata->got_bytes);
cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
+ case MID_RESPONSE_MALFORMED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed);
+ rdata->result = smb_EIO(smb_eio_trace_read_rsp_malformed);
+ break;
default:
- rdata->result = -EIO;
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown);
+ rdata->result = smb_EIO1(smb_eio_trace_read_mid_state_unknown,
+ mid->mid_state);
+ break;
}
if (rdata->result == -ENODATA) {
rdata->result = 0;
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
+ trace_smb3_read_err(rdata->rreq->debug_id,
+ rdata->subreq.debug_index,
+ rdata->xid,
+ rdata->req->cfile->fid.persistent_fid,
+ tcon->tid, tcon->ses->Suid,
+ rdata->subreq.start + rdata->subreq.transferred,
+ rdata->subreq.len - rdata->subreq.transferred,
+ rdata->result);
} else {
size_t trans = rdata->subreq.transferred + rdata->got_bytes;
if (trans < rdata->subreq.len &&
- rdata->subreq.start + trans == ictx->remote_i_size) {
+ rdata->subreq.start + trans >= ictx->remote_i_size) {
rdata->result = 0;
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
} else if (rdata->got_bytes > 0) {
@@ -1360,15 +1546,28 @@ cifs_readv_callback(struct mid_q_entry *mid)
}
if (rdata->got_bytes)
__set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags);
+ trace_smb3_read_done(rdata->rreq->debug_id,
+ rdata->subreq.debug_index,
+ rdata->xid,
+ rdata->req->cfile->fid.persistent_fid,
+ tcon->tid, tcon->ses->Suid,
+ rdata->subreq.start + rdata->subreq.transferred,
+ rdata->got_bytes);
}
+ trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
+ server->credits, server->in_flight,
+ 0, cifs_trace_rw_credits_read_response_clear);
rdata->credits.value = 0;
rdata->subreq.error = rdata->result;
rdata->subreq.transferred += rdata->got_bytes;
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
netfs_read_subreq_terminated(&rdata->subreq);
- release_mid(mid);
+ release_mid(server, mid);
add_credits(server, &credits, 0);
+ trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
+ server->credits, server->in_flight,
+ credits.value, cifs_trace_rw_credits_read_response_add);
}
/* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -1380,7 +1579,8 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
int wct;
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
struct smb_rqst rqst = { .rq_iov = rdata->iov,
- .rq_nvec = 2 };
+ .rq_nvec = 1 };
+ unsigned int in_len;
cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
__func__, rdata->subreq.start, rdata->subreq.len);
@@ -1391,13 +1591,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
wct = 10; /* old style read */
if ((rdata->subreq.start >> 32) > 0) {
/* can not handle this big offset for old */
- return -EIO;
+ return smb_EIO(smb_eio_trace_read_too_far);
}
}
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
smb->hdr.Pid = cpu_to_le16((__u16)rdata->req->pid);
smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->req->pid >> 16));
@@ -1421,9 +1622,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
/* 4 for RFC1001 length + 1 for BCC */
rdata->iov[0].iov_base = smb;
- rdata->iov[0].iov_len = 4;
- rdata->iov[1].iov_base = (char *)smb + 4;
- rdata->iov[1].iov_len = get_rfc1002_length(smb);
+ rdata->iov[0].iov_len = in_len;
+
+ trace_smb3_read_enter(rdata->rreq->debug_id,
+ rdata->subreq.debug_index,
+ rdata->xid,
+ rdata->req->cfile->fid.netfid,
+ tcon->tid, tcon->ses->Suid,
+ rdata->subreq.start, rdata->subreq.len);
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
cifs_readv_callback, NULL, rdata, 0, NULL);
@@ -1450,6 +1656,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
__u16 netfid = io_parms->netfid;
__u64 offset = io_parms->offset;
struct cifs_tcon *tcon = io_parms->tcon;
+ unsigned int in_len;
unsigned int count = io_parms->length;
cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
@@ -1459,14 +1666,15 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
wct = 10; /* old style read */
if ((offset >> 32) > 0) {
/* can not handle this big offset for old */
- return -EIO;
+ return smb_EIO(smb_eio_trace_read_too_far);
}
}
*nbytes = 0;
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
@@ -1494,7 +1702,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
}
iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
+ iov[0].iov_len = in_len;
rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
CIFS_LOG_ERROR, &rsp_iov);
cifs_small_buf_release(pSMB);
@@ -1513,7 +1721,8 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
|| (data_length > count)) {
cifs_dbg(FYI, "bad length %d for count %d\n",
data_length, count);
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_read_overlarge,
+ data_length, count);
*nbytes = 0;
} else {
pReadData = (char *) (&pSMBr->hdr.Protocol) +
@@ -1558,7 +1767,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
__u16 netfid = io_parms->netfid;
__u64 offset = io_parms->offset;
struct cifs_tcon *tcon = io_parms->tcon;
- unsigned int count = io_parms->length;
+ unsigned int count = io_parms->length, in_len;
*nbytes = 0;
@@ -1572,14 +1781,15 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
wct = 12;
if ((offset >> 32) > 0) {
/* can not handle big offset for old srv */
- return -EIO;
+ return smb_EIO(smb_eio_trace_write_too_far);
}
}
rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
@@ -1612,7 +1822,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
if (bytes_sent > count)
bytes_sent = count;
pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+ cpu_to_le16(offsetof(struct smb_com_write_req, Data));
if (buf)
memcpy(pSMB->Data, buf, bytes_sent);
else if (count != 0) {
@@ -1627,7 +1837,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
if (wct == 14)
pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -1638,7 +1848,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
pSMBW->ByteCount = cpu_to_le16(byte_count);
}
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
if (rc) {
@@ -1670,10 +1880,9 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
* workqueue completion task.
*/
static void
-cifs_writev_callback(struct mid_q_entry *mid)
+cifs_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
struct cifs_io_subrequest *wdata = mid->callback_data;
- struct TCP_Server_Info *server = wdata->server;
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
struct cifs_credits credits = {
@@ -1712,11 +1921,23 @@ cifs_writev_callback(struct mid_q_entry *mid)
}
break;
case MID_REQUEST_SUBMITTED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_req_submitted);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ result = -EAGAIN;
+ break;
case MID_RETRY_NEEDED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
result = -EAGAIN;
break;
+ case MID_RESPONSE_MALFORMED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_malformed);
+ result = smb_EIO(smb_eio_trace_write_rsp_malformed);
+ break;
default:
- result = -EIO;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown);
+ result = smb_EIO1(smb_eio_trace_write_mid_state_unknown,
+ mid->mid_state);
break;
}
@@ -1725,8 +1946,8 @@ cifs_writev_callback(struct mid_q_entry *mid)
server->credits, server->in_flight,
0, cifs_trace_rw_credits_write_response_clear);
wdata->credits.value = 0;
- cifs_write_subrequest_terminated(wdata, result, true);
- release_mid(mid);
+ cifs_write_subrequest_terminated(wdata, result);
+ release_mid(server, mid);
trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0,
server->credits, server->in_flight,
credits.value, cifs_trace_rw_credits_write_response_add);
@@ -1738,11 +1959,12 @@ void
cifs_async_writev(struct cifs_io_subrequest *wdata)
{
int rc = -EACCES;
- WRITE_REQ *smb = NULL;
+ WRITE_REQ *req = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
- struct kvec iov[2];
+ struct kvec iov[1];
struct smb_rqst rqst = { };
+ unsigned int in_len;
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
wct = 14;
@@ -1750,56 +1972,54 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
wct = 12;
if (wdata->subreq.start >> 32 > 0) {
/* can not handle big offset for old srv */
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_write_too_far);
goto out;
}
}
- rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
- if (rc)
+ rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&req);
+ if (rc < 0)
goto async_writev_out;
+ in_len = rc;
- smb->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid);
- smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16));
+ req->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid);
+ req->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16));
- smb->AndXCommand = 0xFF; /* none */
- smb->Fid = wdata->req->cfile->fid.netfid;
- smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
+ req->AndXCommand = 0xFF; /* none */
+ req->Fid = wdata->req->cfile->fid.netfid;
+ req->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
if (wct == 14)
- smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
- smb->Reserved = 0xFFFFFFFF;
- smb->WriteMode = 0;
- smb->Remaining = 0;
+ req->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
+ req->Reserved = 0xFFFFFFFF;
+ req->WriteMode = 0;
+ req->Remaining = 0;
- smb->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+ req->DataOffset =
+ cpu_to_le16(offsetof(struct smb_com_write_req, Data));
- /* 4 for RFC1001 length + 1 for BCC */
- iov[0].iov_len = 4;
- iov[0].iov_base = smb;
- iov[1].iov_len = get_rfc1002_length(smb) + 1;
- iov[1].iov_base = (char *)smb + 4;
+ iov[0].iov_base = req;
+ iov[0].iov_len = in_len + 1; /* +1 for BCC */
rqst.rq_iov = iov;
- rqst.rq_nvec = 2;
+ rqst.rq_nvec = 1;
rqst.rq_iter = wdata->subreq.io_iter;
cifs_dbg(FYI, "async write at %llu %zu bytes\n",
wdata->subreq.start, wdata->subreq.len);
- smb->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF);
- smb->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16);
+ req->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF);
+ req->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16);
if (wct == 14) {
- inc_rfc1001_len(&smb->hdr, wdata->subreq.len + 1);
- put_bcc(wdata->subreq.len + 1, &smb->hdr);
+ in_len += wdata->subreq.len + 1;
+ put_bcc(wdata->subreq.len + 1, &req->hdr);
} else {
/* wct == 12 */
- struct smb_com_writex_req *smbw =
- (struct smb_com_writex_req *)smb;
- inc_rfc1001_len(&smbw->hdr, wdata->subreq.len + 5);
- put_bcc(wdata->subreq.len + 5, &smbw->hdr);
- iov[1].iov_len += 4; /* pad bigger by four bytes */
+ struct smb_com_writex_req *reqw =
+ (struct smb_com_writex_req *)req;
+ in_len += wdata->subreq.len + 5;
+ put_bcc(wdata->subreq.len + 5, &reqw->hdr);
+ iov[0].iov_len += 4; /* pad bigger by four bytes */
}
rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
@@ -1809,11 +2029,11 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
async_writev_out:
- cifs_small_buf_release(smb);
+ cifs_small_buf_release(req);
out:
if (rc) {
add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
- cifs_write_subrequest_terminated(wdata, rc, false);
+ cifs_write_subrequest_terminated(wdata, rc);
}
}
@@ -1832,6 +2052,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
struct cifs_tcon *tcon = io_parms->tcon;
unsigned int count = io_parms->length;
struct kvec rsp_iov;
+ unsigned int in_len;
*nbytes = 0;
@@ -1843,12 +2064,13 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
wct = 12;
if ((offset >> 32) > 0) {
/* can not handle big offset for old srv */
- return -EIO;
+ return smb_EIO(smb_eio_trace_write_too_far);
}
}
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
@@ -1867,16 +2089,16 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
pSMB->Remaining = 0;
pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+ cpu_to_le16(offsetof(struct smb_com_write_req, Data));
pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
/* header + 1 byte pad */
- smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
+ smb_hdr_len = in_len + 1;
if (wct == 14)
- inc_rfc1001_len(pSMB, count + 1);
+ in_len += count + 1;
else /* wct == 12 */
- inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
+ in_len += count + 5; /* smb data starts later */
if (wct == 14)
pSMB->ByteCount = cpu_to_le16(count + 1);
else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
@@ -1898,7 +2120,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
} else if (resp_buf_type == 0) {
/* presumably this can not happen, but best to be safe */
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_write_bad_buf_type, resp_buf_type);
} else {
WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
*nbytes = le16_to_cpu(pSMBr->CountHigh);
@@ -1930,6 +2152,7 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
LOCK_REQ *pSMB = NULL;
struct kvec iov[2];
struct kvec rsp_iov;
+ unsigned int in_len;
int resp_buf_type;
__u16 count;
@@ -1937,8 +2160,9 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
num_lock, num_unlock);
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->Timeout = 0;
pSMB->NumberOfLocks = cpu_to_le16(num_lock);
@@ -1948,11 +2172,11 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Fid = netfid; /* netfid stays le */
count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
+ iov[0].iov_len = in_len -
(num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
iov[1].iov_base = (char *)buf;
iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
@@ -1977,16 +2201,18 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
LOCK_REQ *pSMB = NULL;
/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
+ unsigned int in_len;
int bytes_returned;
- int flags = 0;
+ int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT;
__u16 count;
cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
(int)waitFlag, numLock);
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
/* no response expected */
@@ -2018,14 +2244,15 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
/* oplock break */
count = 0;
}
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
if (waitFlag)
- rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMB, &bytes_returned);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
+ (struct smb_hdr *) pSMB, &bytes_returned,
+ flags);
else
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, in_len, flags);
cifs_small_buf_release(pSMB);
cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
if (rc)
@@ -2046,8 +2273,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
struct cifs_posix_lock *parm_data;
+ unsigned int in_len;
int rc = 0;
- int timeout = 0;
+ int sr_flags = CIFS_INTERRUPTIBLE_WAIT;
int bytes_returned = 0;
int resp_buf_type = 0;
__u16 params, param_offset, offset, byte_count, count;
@@ -2057,9 +2285,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
cifs_dbg(FYI, "Posix Lock\n");
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
-
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
@@ -2068,7 +2296,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
count = sizeof(struct cifs_posix_lock);
@@ -2086,13 +2314,11 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- parm_data = (struct cifs_posix_lock *)
- (((char *)pSMB) + offset + 4);
+ parm_data = (struct cifs_posix_lock *)(((char *)pSMB) + offset);
parm_data->lock_type = cpu_to_le16(lock_type);
if (waitFlag) {
- timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
+ sr_flags |= CIFS_BLOCKING_OP; /* blocking operation, no timeout */
parm_data->lock_flags = cpu_to_le16(1);
pSMB->Timeout = cpu_to_le32(-1);
} else
@@ -2106,16 +2332,17 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Fid = smb_file_id;
pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
if (waitFlag) {
- rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
+ (struct smb_hdr *) pSMBr, &bytes_returned,
+ sr_flags);
} else {
iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
+ iov[0].iov_len = in_len;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
- &resp_buf_type, timeout, &rsp_iov);
+ &resp_buf_type, sr_flags, &rsp_iov);
pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
}
cifs_small_buf_release(pSMB);
@@ -2129,13 +2356,15 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_lock_bcc_too_small,
+ get_bcc(&pSMBr->hdr), sizeof(*parm_data));
goto plk_err_exit;
}
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
data_count = le16_to_cpu(pSMBr->t2.DataCount);
if (data_count < sizeof(struct cifs_posix_lock)) {
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_lock_data_too_small,
+ data_count, sizeof(struct cifs_posix_lock));
goto plk_err_exit;
}
parm_data = (struct cifs_posix_lock *)
@@ -2173,19 +2402,22 @@ CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
{
int rc = 0;
CLOSE_REQ *pSMB = NULL;
+ unsigned int in_len;
+
cifs_dbg(FYI, "In CIFSSMBClose\n");
/* do not retry on dead session on close */
rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
if (rc == -EAGAIN)
return 0;
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->FileID = (__u16) smb_file_id;
pSMB->LastWriteTime = 0xFFFFFFFF;
pSMB->ByteCount = 0;
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
if (rc) {
@@ -2207,15 +2439,18 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
{
int rc = 0;
FLUSH_REQ *pSMB = NULL;
+ unsigned int in_len;
+
cifs_dbg(FYI, "In CIFSSMBFlush\n");
rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->FileID = (__u16) smb_file_id;
pSMB->ByteCount = 0;
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
if (rc)
@@ -2232,6 +2467,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
RENAME_REQ *pSMB = NULL;
RENAME_RSP *pSMBr = NULL;
+ unsigned int in_len;
int bytes_returned;
int name_len, name_len2;
__u16 count;
@@ -2241,8 +2477,9 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
renameRetry:
rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->BufferFormat = 0x04;
pSMB->SearchAttributes =
@@ -2272,10 +2509,10 @@ renameRetry:
}
count = 1 /* 1st signature byte */ + name_len + name_len2;
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
if (rc)
@@ -2296,6 +2533,7 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
struct set_file_rename *rename_info;
+ unsigned int in_len;
char *data_offset;
char dummy_string[30];
int rc = 0;
@@ -2306,8 +2544,9 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
cifs_dbg(FYI, "Rename to File by handle\n");
rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 6;
pSMB->MaxSetupCount = 0;
@@ -2315,11 +2554,10 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- data_offset = (char *)(pSMB) + offset + 4;
+ data_offset = (char *)(pSMB) + offset;
rename_info = (struct set_file_rename *) data_offset;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
@@ -2355,9 +2593,9 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
if (rc)
@@ -2379,6 +2617,7 @@ CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
char *data_offset;
int name_len;
int name_len_target;
@@ -2390,8 +2629,9 @@ CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
createSymLinkRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -2411,11 +2651,10 @@ createSymLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- data_offset = (char *)pSMB + offset + 4;
+ data_offset = (char *)pSMB + offset;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len_target =
cifsConvertToUTF16((__le16 *) data_offset, toName,
@@ -2442,9 +2681,9 @@ createSymLinkRetry:
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
if (rc)
@@ -2466,6 +2705,7 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
char *data_offset;
int name_len;
int name_len_target;
@@ -2477,8 +2717,9 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
createHardLinkRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
@@ -2496,11 +2737,10 @@ createHardLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- data_offset = (char *)pSMB + offset + 4;
+ data_offset = (char *)pSMB + offset;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len_target =
cifsConvertToUTF16((__le16 *) data_offset, fromName,
@@ -2526,9 +2766,9 @@ createHardLinkRetry:
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
if (rc)
@@ -2551,6 +2791,7 @@ int CIFSCreateHardLink(const unsigned int xid,
int rc = 0;
NT_RENAME_REQ *pSMB = NULL;
RENAME_RSP *pSMBr = NULL;
+ unsigned int in_len;
int bytes_returned;
int name_len, name_len2;
__u16 count;
@@ -2561,8 +2802,9 @@ winCreateHardLinkRetry:
rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->SearchAttributes =
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
@@ -2596,10 +2838,10 @@ winCreateHardLinkRetry:
}
count = 1 /* string type byte */ + name_len + name_len2;
- inc_rfc1001_len(pSMB, count);
+ in_len += count;
pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
if (rc)
@@ -2620,6 +2862,7 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
/* SMB_QUERY_FILE_UNIX_LINK */
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -2631,8 +2874,9 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
querySymLinkRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -2655,7 +2899,7 @@ querySymLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -2666,10 +2910,10 @@ querySymLinkRetry:
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
@@ -2679,7 +2923,8 @@ querySymLinkRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
/* BB also check enough total bytes returned */
if (rc || get_bcc(&pSMBr->hdr) < 2)
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qsym_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 2);
else {
bool is_unicode;
u16 count = le16_to_cpu(pSMBr->t2.DataCount);
@@ -2717,6 +2962,7 @@ int cifs_query_reparse_point(const unsigned int xid,
TRANSACT_IOCTL_REQ *io_req = NULL;
TRANSACT_IOCTL_RSP *io_rsp = NULL;
struct cifs_fid fid;
+ unsigned int in_len;
__u32 data_offset, data_count, len;
__u8 *start, *end;
int io_rsp_len;
@@ -2728,7 +2974,7 @@ int cifs_query_reparse_point(const unsigned int xid,
if (cap_unix(tcon->ses))
return -EOPNOTSUPP;
- if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS))
+ if (!CIFS_REPARSE_SUPPORT(tcon))
return -EOPNOTSUPP;
oparms = (struct cifs_open_parms) {
@@ -2748,15 +2994,16 @@ int cifs_query_reparse_point(const unsigned int xid,
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
(void **)&io_req, (void **)&io_rsp);
- if (rc)
+ if (rc < 0)
goto error;
+ in_len = rc;
io_req->TotalParameterCount = 0;
io_req->TotalDataCount = 0;
- io_req->MaxParameterCount = cpu_to_le32(2);
+ io_req->MaxParameterCount = cpu_to_le32(0);
/* BB find exact data count max from sess structure BB */
io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
- io_req->MaxSetupCount = 4;
+ io_req->MaxSetupCount = 1;
io_req->Reserved = 0;
io_req->ParameterOffset = 0;
io_req->DataCount = 0;
@@ -2770,7 +3017,7 @@ int cifs_query_reparse_point(const unsigned int xid,
io_req->Fid = fid.netfid;
io_req->ByteCount = 0;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, in_len,
(struct smb_hdr *)io_rsp, &io_rsp_len, 0);
if (rc)
goto error;
@@ -2779,14 +3026,35 @@ int cifs_query_reparse_point(const unsigned int xid,
data_count = le32_to_cpu(io_rsp->DataCount);
if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
!data_count || data_count > 2048) {
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qreparse_sizes_wrong,
+ get_bcc(&io_rsp->hdr), data_count);
+ goto error;
+ }
+
+ /* SetupCount must be 1, otherwise offset to ByteCount is incorrect. */
+ if (io_rsp->SetupCount != 1) {
+ rc = smb_EIO2(smb_eio_trace_qreparse_setup_count,
+ io_rsp->SetupCount, 1);
+ goto error;
+ }
+
+ /*
+ * ReturnedDataLen is output length of executed IOCTL.
+ * DataCount is output length transferred over network.
+ * Check that we have full FSCTL_GET_REPARSE_POINT buffer.
+ */
+ if (data_count != le16_to_cpu(io_rsp->ReturnedDataLen)) {
+ rc = smb_EIO2(smb_eio_trace_qreparse_ret_datalen,
+ data_count, le16_to_cpu(io_rsp->ReturnedDataLen));
goto error;
}
end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
if (start >= end) {
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qreparse_data_area,
+ (unsigned long)start - (unsigned long)io_rsp,
+ (unsigned long)end - (unsigned long)io_rsp);
goto error;
}
@@ -2795,7 +3063,8 @@ int cifs_query_reparse_point(const unsigned int xid,
len = sizeof(*buf);
if (data_count < len ||
data_count < le16_to_cpu(buf->ReparseDataLength) + len) {
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qreparse_rep_datalen,
+ data_count, le16_to_cpu(buf->ReparseDataLength) + len);
goto error;
}
@@ -2812,6 +3081,129 @@ error:
return rc;
}
+struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid,
+ struct cifs_tcon *tcon,
+ const char *full_path,
+ bool directory,
+ struct kvec *reparse_iov,
+ struct kvec *xattr_iov)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifs_open_parms oparms;
+ TRANSACT_IOCTL_REQ *io_req;
+ struct inode *new = NULL;
+ struct kvec in_iov[2];
+ struct kvec out_iov;
+ struct cifs_fid fid;
+ unsigned int in_len;
+ int oplock = 0;
+ int buf_type = 0;
+ int rc;
+
+ cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
+
+ /*
+ * If server filesystem does not support reparse points then do not
+ * attempt to create reparse point. This will prevent creating unusable
+ * empty object on the server.
+ */
+ if (!CIFS_REPARSE_SUPPORT(tcon))
+ return ERR_PTR(-EOPNOTSUPP);
+
+#ifndef CONFIG_CIFS_XATTR
+ if (xattr_iov)
+ return ERR_PTR(-EOPNOTSUPP);
+#endif
+
+ oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA,
+ FILE_CREATE,
+ (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
+ ACL_NO_MODE);
+ oparms.fid = &fid;
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc)
+ return ERR_PTR(rc);
+
+#ifdef CONFIG_CIFS_XATTR
+ if (xattr_iov) {
+ struct smb2_file_full_ea_info *ea;
+
+ ea = &((struct smb2_create_ea_ctx *)xattr_iov->iov_base)->ea;
+ while (1) {
+ rc = CIFSSMBSetEA(xid,
+ tcon,
+ full_path,
+ &ea->ea_data[0],
+ &ea->ea_data[ea->ea_name_length+1],
+ le16_to_cpu(ea->ea_value_length),
+ cifs_sb->local_nls,
+ cifs_sb);
+ if (rc)
+ goto out_close;
+ if (le32_to_cpu(ea->next_entry_offset) == 0)
+ break;
+ ea = (struct smb2_file_full_ea_info *)((u8 *)ea +
+ le32_to_cpu(ea->next_entry_offset));
+ }
+ }
+#endif
+
+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **)&io_req, NULL);
+ if (rc < 0)
+ goto out_close;
+ in_len = rc;
+ in_len += sizeof(io_req->Pad);
+
+ /* NT IOCTL response contains one-word long output setup buffer with size of output data. */
+ io_req->MaxSetupCount = 1;
+ /* NT IOCTL response does not contain output parameters. */
+ io_req->MaxParameterCount = cpu_to_le32(0);
+ /* FSCTL_SET_REPARSE_POINT response contains empty output data. */
+ io_req->MaxDataCount = cpu_to_le32(0);
+
+ io_req->TotalParameterCount = cpu_to_le32(0);
+ io_req->TotalDataCount = cpu_to_le32(reparse_iov->iov_len);
+ io_req->ParameterCount = io_req->TotalParameterCount;
+ io_req->ParameterOffset = cpu_to_le32(0);
+ io_req->DataCount = io_req->TotalDataCount;
+ io_req->DataOffset = cpu_to_le32(offsetof(typeof(*io_req), Data));
+ io_req->SetupCount = 4;
+ io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
+ io_req->FunctionCode = cpu_to_le32(FSCTL_SET_REPARSE_POINT);
+ io_req->Fid = fid.netfid;
+ io_req->IsFsctl = 1;
+ io_req->IsRootFlag = 0;
+ io_req->ByteCount = cpu_to_le16(le32_to_cpu(io_req->DataCount) + sizeof(io_req->Pad));
+
+ in_iov[0].iov_base = (char *)io_req;
+ in_iov[0].iov_len = in_len;
+ in_iov[1] = *reparse_iov;
+ rc = SendReceive2(xid, tcon->ses, in_iov, ARRAY_SIZE(in_iov), &buf_type,
+ CIFS_NO_RSP_BUF, &out_iov);
+
+ cifs_buf_release(io_req);
+
+ if (!rc)
+ rc = cifs_get_inode_info(&new, full_path, data, sb, xid, NULL);
+
+out_close:
+ CIFSSMBClose(xid, tcon, fid.netfid);
+
+ /*
+ * If CREATE was successful but FSCTL_SET_REPARSE_POINT failed then
+ * remove the intermediate object created by CREATE. Otherwise
+ * empty object stay on the server when reparse call failed.
+ */
+ if (rc)
+ CIFSSMBDelFile(xid, tcon, full_path, cifs_sb, NULL);
+
+ return rc ? ERR_PTR(rc) : new;
+}
+
int
CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
__u16 fid)
@@ -2820,12 +3212,14 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
int bytes_returned;
struct smb_com_transaction_compr_ioctl_req *pSMB;
struct smb_com_transaction_ioctl_rsp *pSMBr;
+ unsigned int in_len;
cifs_dbg(FYI, "Set compression for %u\n", fid);
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
@@ -2839,7 +3233,7 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->DataCount = cpu_to_le32(2);
pSMB->DataOffset =
cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
- compression_state) - 4); /* 84 */
+ compression_state)); /* 84 */
pSMB->SetupCount = 4;
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
pSMB->ParameterCount = 0;
@@ -2849,9 +3243,9 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Fid = fid; /* file handle always le */
/* 3 byte pad, followed by 2 byte compress state */
pSMB->ByteCount = cpu_to_le16(5);
- inc_rfc1001_len(pSMB, 5);
+ in_len += 5;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
@@ -3049,6 +3443,7 @@ int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -3059,8 +3454,9 @@ int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
queryAclRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -3087,7 +3483,7 @@ queryAclRetry:
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(
offsetof(struct smb_com_transaction2_qpi_req,
- InformationLevel) - 4);
+ InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3098,10 +3494,10 @@ queryAclRetry:
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
if (rc) {
@@ -3112,7 +3508,8 @@ queryAclRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
/* BB also check enough total bytes returned */
if (rc || get_bcc(&pSMBr->hdr) < 2)
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_getacl_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 2);
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
@@ -3139,6 +3536,7 @@ int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+ unsigned int in_len;
char *parm_data;
int name_len;
int rc = 0;
@@ -3149,8 +3547,9 @@ int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
setAclRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
@@ -3170,9 +3569,9 @@ setAclRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset;
+ parm_data = ((char *)pSMB) + offset;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
/* convert to on the wire format for POSIX ACL */
@@ -3193,9 +3592,9 @@ setAclRetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
@@ -3231,6 +3630,7 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
struct smb_t2_qfi_req *pSMB = NULL;
struct smb_t2_qfi_rsp *pSMBr = NULL;
+ unsigned int in_len;
int bytes_returned;
__u16 params, byte_count;
@@ -3241,8 +3641,9 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
GetExtAttrRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2 /* level */ + 2 /* fid */;
pSMB->t2.TotalDataCount = 0;
@@ -3255,7 +3656,7 @@ GetExtAttrRetry:
pSMB->t2.Timeout = 0;
pSMB->t2.Reserved2 = 0;
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
- Fid) - 4);
+ Fid));
pSMB->t2.DataCount = 0;
pSMB->t2.DataOffset = 0;
pSMB->t2.SetupCount = 1;
@@ -3267,10 +3668,10 @@ GetExtAttrRetry:
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
pSMB->Pad = 0;
pSMB->Fid = netfid;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
@@ -3281,7 +3682,8 @@ GetExtAttrRetry:
if (rc || get_bcc(&pSMBr->hdr) < 2)
/* If rc should we check for EOPNOSUPP and
disable the srvino flag? or in caller? */
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_getextattr_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 2);
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
@@ -3289,7 +3691,8 @@ GetExtAttrRetry:
if (count != 16) {
cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_getextattr_inv_size,
+ count, 16);
goto GetExtAttrOut;
}
pfinfo = (struct file_chattr_info *)
@@ -3323,11 +3726,13 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count,
int rc;
__u32 temp_offset;
struct smb_com_ntransact_req *pSMB;
+ unsigned int in_len;
rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
(void **)&pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
*ret_buf = (void *)pSMB;
pSMB->Reserved = 0;
pSMB->TotalParameterCount = cpu_to_le32(parm_len);
@@ -3336,12 +3741,12 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count,
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->DataCount = pSMB->TotalDataCount;
temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
- (setup_count * 2) - 4 /* for rfc1001 length itself */;
+ (setup_count * 2);
pSMB->ParameterOffset = cpu_to_le32(temp_offset);
pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
pSMB->SubCommand = cpu_to_le16(sub_command);
- return 0;
+ return in_len;
}
static int
@@ -3407,6 +3812,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
QUERY_SEC_DESC_REQ *pSMB;
struct kvec iov[1];
struct kvec rsp_iov;
+ unsigned int in_len;
cifs_dbg(FYI, "GetCifsACL\n");
@@ -3415,8 +3821,9 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
8 /* parm len */, tcon, (void **) &pSMB);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->MaxParameterCount = cpu_to_le32(4);
/* BB TEST with big acls that might need to be e.g. larger than 16K */
@@ -3424,9 +3831,9 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
pSMB->Fid = fid; /* file handle always le */
pSMB->AclFlags = cpu_to_le32(info);
pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
- inc_rfc1001_len(pSMB, 11);
+ in_len += 11;
iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
+ iov[0].iov_len = in_len;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
0, &rsp_iov);
@@ -3452,7 +3859,8 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
pSMBr, parm, *acl_inf);
if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_getcifsacl_param_count,
+ le32_to_cpu(pSMBr->ParameterCount), 4);
*pbuflen = 0;
goto qsec_out;
}
@@ -3495,18 +3903,20 @@ CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
int rc = 0;
int bytes_returned = 0;
SET_SEC_DESC_REQ *pSMB = NULL;
+ unsigned int in_len;
void *pSMBr;
setCifsAclRetry:
rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
param_count = 8;
- param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid);
data_count = acllen;
data_offset = param_offset + param_count;
byte_count = 3 /* pad */ + param_count;
@@ -3528,13 +3938,12 @@ setCifsAclRetry:
pSMB->AclFlags = cpu_to_le32(aclflag);
if (pntsd && acllen) {
- memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
- data_offset, pntsd, acllen);
- inc_rfc1001_len(pSMB, byte_count + data_count);
+ memcpy((char *)pSMBr + data_offset, pntsd, acllen);
+ in_len += byte_count + data_count;
} else
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
@@ -3559,6 +3968,7 @@ SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
{
QUERY_INFORMATION_REQ *pSMB;
QUERY_INFORMATION_RSP *pSMBr;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -3567,8 +3977,9 @@ SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
QInfRetry:
rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -3582,10 +3993,10 @@ QInfRetry:
}
pSMB->BufferFormat = 0x04;
name_len++; /* account for buffer type byte */
- inc_rfc1001_len(pSMB, (__u16)name_len);
+ in_len += name_len;
pSMB->ByteCount = cpu_to_le16(name_len);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
@@ -3607,8 +4018,10 @@ QInfRetry:
data->EndOfFile = data->AllocationSize;
data->Attributes =
cpu_to_le32(le16_to_cpu(pSMBr->attr));
- } else
- rc = -EIO; /* bad buffer passed in */
+ } else {
+ /* bad buffer passed in */
+ rc = smb_EIO(smb_eio_trace_null_pointers);
+ }
cifs_buf_release(pSMB);
@@ -3624,6 +4037,7 @@ CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
{
struct smb_t2_qfi_req *pSMB = NULL;
struct smb_t2_qfi_rsp *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
__u16 params, byte_count;
@@ -3631,8 +4045,9 @@ CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
QFileInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2 /* level */ + 2 /* fid */;
pSMB->t2.TotalDataCount = 0;
@@ -3645,7 +4060,7 @@ QFileInfoRetry:
pSMB->t2.Timeout = 0;
pSMB->t2.Reserved2 = 0;
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
- Fid) - 4);
+ Fid));
pSMB->t2.DataCount = 0;
pSMB->t2.DataOffset = 0;
pSMB->t2.SetupCount = 1;
@@ -3657,10 +4072,10 @@ QFileInfoRetry:
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
pSMB->Pad = 0;
pSMB->Fid = netfid;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
@@ -3668,9 +4083,11 @@ QFileInfoRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc) /* BB add auto retry on EOPNOTSUPP? */
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qfileinfo_invalid,
+ get_bcc(&pSMBr->hdr), 40);
else if (get_bcc(&pSMBr->hdr) < 40)
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfileinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 40);
else if (pFindData) {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
memcpy((char *) pFindData,
@@ -3695,6 +4112,7 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
/* level 263 SMB_QUERY_FILE_ALL_INFO */
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -3704,8 +4122,9 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
QPathInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -3728,7 +4147,7 @@ QPathInfoRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3742,10 +4161,10 @@ QPathInfoRetry:
else
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
@@ -3753,12 +4172,15 @@ QPathInfoRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc) /* BB add auto retry on EOPNOTSUPP? */
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qpathinfo_invalid,
+ get_bcc(&pSMBr->hdr), 40);
else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qpathinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 40);
else if (legacy && get_bcc(&pSMBr->hdr) < 24)
- rc = -EIO; /* 24 or 26 expected but we do not read
- last field */
+ /* 24 or 26 expected but we do not read last field */
+ rc = smb_EIO2(smb_eio_trace_qpathinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 24);
else if (data) {
int size;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@@ -3791,6 +4213,7 @@ CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
{
struct smb_t2_qfi_req *pSMB = NULL;
struct smb_t2_qfi_rsp *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
__u16 params, byte_count;
@@ -3798,8 +4221,9 @@ CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
UnixQFileInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2 /* level */ + 2 /* fid */;
pSMB->t2.TotalDataCount = 0;
@@ -3812,7 +4236,7 @@ UnixQFileInfoRetry:
pSMB->t2.Timeout = 0;
pSMB->t2.Reserved2 = 0;
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
- Fid) - 4);
+ Fid));
pSMB->t2.DataCount = 0;
pSMB->t2.DataOffset = 0;
pSMB->t2.SetupCount = 1;
@@ -3824,10 +4248,10 @@ UnixQFileInfoRetry:
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
pSMB->Pad = 0;
pSMB->Fid = netfid;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
@@ -3836,7 +4260,8 @@ UnixQFileInfoRetry:
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_unixqfileinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO));
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
memcpy((char *) pFindData,
@@ -3862,6 +4287,7 @@ CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
/* SMB_QUERY_FILE_UNIX_BASIC */
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
int name_len;
@@ -3871,8 +4297,9 @@ CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
UnixQPathInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -3895,7 +4322,7 @@ UnixQPathInfoRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3906,10 +4333,10 @@ UnixQPathInfoRetry:
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
@@ -3918,7 +4345,8 @@ UnixQPathInfoRetry:
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_unixqpathinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO));
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
memcpy((char *) pFindData,
@@ -3946,7 +4374,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
T2_FFIRST_RSP_PARMS *parms;
struct nls_table *nls_codepage;
- unsigned int lnoff;
+ unsigned int in_len, lnoff;
__u16 params, byte_count;
int bytes_returned = 0;
int name_len, remap;
@@ -3957,8 +4385,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
findFirstRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
nls_codepage = cifs_sb->local_nls;
remap = cifs_remap(cifs_sb);
@@ -3981,6 +4410,12 @@ findFirstRetry:
pSMB->FileName[name_len] = 0;
pSMB->FileName[name_len+1] = 0;
name_len += 2;
+ } else if (!searchName[0]) {
+ pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb);
+ pSMB->FileName[1] = 0;
+ pSMB->FileName[2] = 0;
+ pSMB->FileName[3] = 0;
+ name_len = 4;
}
} else {
name_len = copy_path_name(pSMB->FileName, searchName);
@@ -3992,6 +4427,10 @@ findFirstRetry:
pSMB->FileName[name_len] = '*';
pSMB->FileName[name_len+1] = 0;
name_len += 2;
+ } else if (!searchName[0]) {
+ pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb);
+ pSMB->FileName[1] = 0;
+ name_len = 2;
}
}
@@ -4008,8 +4447,7 @@ findFirstRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
- - 4);
+ offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
@@ -4018,16 +4456,16 @@ findFirstRetry:
pSMB->SearchAttributes =
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
ATTR_DIRECTORY);
- pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
+ pSMB->SearchCount = cpu_to_le16(msearch ? CIFSMaxBufSize/sizeof(FILE_UNIX_INFO) : 1);
pSMB->SearchFlags = cpu_to_le16(search_flags);
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
/* BB what should we set StorageType to? Does it matter? BB */
pSMB->SearchStorageType = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
@@ -4086,7 +4524,7 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
T2_FNEXT_RSP_PARMS *parms;
- unsigned int name_len;
+ unsigned int name_len, in_len;
unsigned int lnoff;
__u16 params, byte_count;
char *response_data;
@@ -4100,8 +4538,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 14; /* includes 2 bytes of null string, converted to LE below*/
byte_count = 0;
@@ -4114,7 +4553,7 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
+ offsetof(struct smb_com_transaction2_fnext_req, SearchHandle));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -4142,10 +4581,10 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
@@ -4211,6 +4650,7 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
{
int rc = 0;
FINDCLOSE_REQ *pSMB = NULL;
+ unsigned int in_len;
cifs_dbg(FYI, "In CIFSSMBFindClose\n");
rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
@@ -4219,12 +4659,13 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
as file handle has been closed */
if (rc == -EAGAIN)
return 0;
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->FileID = searchHandle;
pSMB->ByteCount = 0;
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
if (rc)
cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
@@ -4246,6 +4687,7 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int name_len, bytes_returned;
__u16 params, byte_count;
@@ -4256,8 +4698,9 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
GetInodeNumberRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -4281,7 +4724,7 @@ GetInodeNumberRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -4292,10 +4735,10 @@ GetInodeNumberRetry:
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
@@ -4306,7 +4749,8 @@ GetInodeNumberRetry:
if (rc || get_bcc(&pSMBr->hdr) < 2)
/* If rc should we check for EOPNOSUPP and
disable the srvino flag? or in caller? */
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_getsrvinonum_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 2);
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
@@ -4314,7 +4758,8 @@ GetInodeNumberRetry:
/* BB Do we need a cast or hash here ? */
if (count < 8) {
cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_getsrvinonum_size,
+ count, 8);
goto GetInodeNumOut;
}
pfinfo = (struct file_internal_info *)
@@ -4338,6 +4783,7 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
/* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -4357,8 +4803,9 @@ getDFSRetry:
*/
rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
(void **)&pSMB, (void **)&pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
/* server pointer checked in called function,
but should never be null here anyway */
@@ -4400,7 +4847,7 @@ getDFSRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+ struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel));
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
@@ -4408,10 +4855,10 @@ getDFSRetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->MaxReferralLevel = cpu_to_le16(3);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
@@ -4421,7 +4868,8 @@ getDFSRetry:
/* BB Also check if enough total bytes returned? */
if (rc || get_bcc(&pSMBr->hdr) < 17) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_getdfsrefer_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 17);
goto GetDFSRefExit;
}
@@ -4453,6 +4901,7 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
FILE_SYSTEM_ALLOC_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4461,8 +4910,9 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
oldQFSInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4477,17 +4927,17 @@ oldQFSInfoRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
@@ -4495,7 +4945,8 @@ oldQFSInfoRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < 18)
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_oldqfsinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 18);
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
@@ -4539,7 +4990,8 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_INFO *response_data;
+ FILE_SYSTEM_SIZE_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4548,8 +5000,9 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
QFSInfoRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4564,17 +5017,17 @@ QFSInfoRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
@@ -4582,12 +5035,13 @@ QFSInfoRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < 24)
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfsinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 24);
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
- (FILE_SYSTEM_INFO
+ (FILE_SYSTEM_SIZE_INFO
*) (((char *) &pSMBr->hdr.Protocol) +
data_offset);
FSData->f_bsize =
@@ -4604,7 +5058,7 @@ QFSInfoRetry:
FSData->f_blocks =
le64_to_cpu(response_data->TotalAllocationUnits);
FSData->f_bfree = FSData->f_bavail =
- le64_to_cpu(response_data->FreeAllocationUnits);
+ le64_to_cpu(response_data->AvailableAllocationUnits);
cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
(unsigned long long)FSData->f_blocks,
(unsigned long long)FSData->f_bfree,
@@ -4626,6 +5080,7 @@ CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4634,8 +5089,9 @@ CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
QFSAttributeRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4651,17 +5107,17 @@ QFSAttributeRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
@@ -4670,7 +5126,8 @@ QFSAttributeRetry:
if (rc || get_bcc(&pSMBr->hdr) < 13) {
/* BB also check if enough bytes returned */
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfsattrinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 13);
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
@@ -4696,6 +5153,7 @@ CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
FILE_SYSTEM_DEVICE_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4704,8 +5162,9 @@ CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
QFSDeviceRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4721,7 +5180,7 @@ QFSDeviceRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
@@ -4729,10 +5188,10 @@ QFSDeviceRetry:
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
@@ -4741,7 +5200,9 @@ QFSDeviceRetry:
if (rc || get_bcc(&pSMBr->hdr) <
sizeof(FILE_SYSTEM_DEVICE_INFO))
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfsdevinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr),
+ sizeof(FILE_SYSTEM_DEVICE_INFO));
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
@@ -4767,6 +5228,7 @@ CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
FILE_SYSTEM_UNIX_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4775,8 +5237,9 @@ CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
QFSUnixRetry:
rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
(void **) &pSMB, (void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4794,15 +5257,15 @@ QFSUnixRetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
@@ -4810,7 +5273,8 @@ QFSUnixRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < 13) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfsunixinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 13);
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
@@ -4836,6 +5300,7 @@ CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
TRANSACTION2_SETFSI_REQ *pSMB = NULL;
TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, param_offset, offset, byte_count;
@@ -4845,8 +5310,9 @@ SETFSUnixRetry:
/* BB switch to small buf init to save memory */
rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
(void **) &pSMB, (void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 4; /* 2 bytes zero followed by info level. */
pSMB->MaxSetupCount = 0;
@@ -4854,8 +5320,7 @@ SETFSUnixRetry:
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
- - 4;
+ param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum);
offset = param_offset + params;
pSMB->MaxParameterCount = cpu_to_le16(4);
@@ -4882,10 +5347,10 @@ SETFSUnixRetry:
pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
pSMB->ClientUnixCap = cpu_to_le64(cap);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
@@ -4912,6 +5377,7 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_QFSI_REQ *pSMB = NULL;
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
FILE_SYSTEM_POSIX_INFO *response_data;
+ unsigned int in_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, byte_count;
@@ -4920,8 +5386,9 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
QFSPosixRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
params = 2; /* level */
pSMB->TotalDataCount = 0;
@@ -4939,15 +5406,15 @@ QFSPosixRetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ smb_com_transaction2_qfsi_req, InformationLevel));
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
@@ -4955,7 +5422,8 @@ QFSPosixRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < 13) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qfsposixinfo_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 13);
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
@@ -5012,6 +5480,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
struct file_end_of_file_info *parm_data;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -5023,8 +5492,9 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
SetEOFRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -5045,7 +5515,7 @@ SetEOFRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
if (set_allocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
@@ -5077,10 +5547,10 @@ SetEOFRetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
parm_data->FileSize = cpu_to_le64(size);
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
@@ -5099,15 +5569,16 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct file_end_of_file_info *parm_data;
+ unsigned int in_len;
int rc = 0;
__u16 params, param_offset, offset, byte_count, count;
cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
(long long)size);
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
-
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
@@ -5118,7 +5589,7 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
count = sizeof(struct file_end_of_file_info);
@@ -5134,9 +5605,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
parm_data =
- (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
+ (struct file_end_of_file_info *)(((char *)pSMB) + offset);
pSMB->DataOffset = cpu_to_le16(offset);
parm_data->FileSize = cpu_to_le64(size);
pSMB->Fid = cfile->fid.netfid;
@@ -5156,9 +5626,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
}
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
if (rc) {
cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
@@ -5171,6 +5641,65 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+int
+SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, __le32 attributes, __le64 write_time,
+ const struct nls_table *nls_codepage,
+ struct cifs_sb_info *cifs_sb)
+{
+ SETATTR_REQ *pSMB;
+ SETATTR_RSP *pSMBr;
+ struct timespec64 ts;
+ unsigned int in_len;
+ int bytes_returned;
+ int name_len;
+ int rc;
+
+ cifs_dbg(FYI, "In %s path %s\n", __func__, fileName);
+
+retry:
+ rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc < 0)
+ return rc;
+ in_len = rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifsConvertToUTF16((__le16 *) pSMB->fileName,
+ fileName, PATH_MAX, nls_codepage,
+ cifs_remap(cifs_sb));
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else {
+ name_len = copy_path_name(pSMB->fileName, fileName);
+ }
+ /* Only few attributes can be set by this command, others are not accepted by Win9x. */
+ pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) &
+ (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE));
+ /* Zero write time value (in both NT and SETATTR formats) means to not change it. */
+ if (le64_to_cpu(write_time) != 0) {
+ ts = cifs_NTtimeToUnix(write_time);
+ pSMB->last_write_time = cpu_to_le32(ts.tv_sec);
+ }
+ pSMB->BufferFormat = 0x04;
+ name_len++; /* account for buffer type byte */
+ in_len += name_len;
+ pSMB->ByteCount = cpu_to_le16(name_len);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc)
+ cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc);
+
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto retry;
+
+ return rc;
+}
+
/* Some legacy servers such as NT4 require that the file times be set on
an open handle, rather than by pathname - this is awkward due to
potential access conflicts on the open, but it is unavoidable for these
@@ -5182,15 +5711,16 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ unsigned int in_len;
char *data_offset;
int rc = 0;
__u16 params, param_offset, offset, byte_count, count;
cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
-
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
@@ -5201,11 +5731,10 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
- data_offset = (char *)pSMB +
- offsetof(struct smb_hdr, Protocol) + offset;
+ data_offset = (char *)pSMB + offset;
count = sizeof(FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5227,10 +5756,10 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
else
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
if (rc)
cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
@@ -5247,15 +5776,16 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
bool delete_file, __u16 fid, __u32 pid_of_opener)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ unsigned int in_len;
char *data_offset;
int rc = 0;
__u16 params, param_offset, offset, byte_count, count;
cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
-
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
@@ -5266,11 +5796,9 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
-
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- data_offset = (char *)(pSMB) + offset + 4;
+ data_offset = (char *)(pSMB) + offset;
count = 1;
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5289,10 +5817,10 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Fid = fid;
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
*data_offset = delete_file ? 1 : 0;
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
if (rc)
cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
@@ -5340,6 +5868,7 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -5352,8 +5881,9 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
SetTimesRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -5376,7 +5906,7 @@ SetTimesRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
data_offset = (char *)pSMB + offsetof(typeof(*pSMB), hdr.Protocol) + offset;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
@@ -5395,10 +5925,10 @@ SetTimesRetry:
else
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
@@ -5468,15 +5998,16 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
u16 fid, u32 pid_of_opener)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ unsigned int in_len;
char *data_offset;
int rc = 0;
u16 params, param_offset, offset, byte_count, count;
cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
-
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
@@ -5487,11 +6018,10 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid);
offset = param_offset + params;
- data_offset = (char *)pSMB +
- offsetof(struct smb_hdr, Protocol) + offset;
+ data_offset = (char *)pSMB + offset;
count = sizeof(FILE_UNIX_BASIC_INFO);
@@ -5511,12 +6041,12 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Fid = fid;
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
- rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+ rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0);
cifs_small_buf_release(pSMB);
if (rc)
cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
@@ -5536,6 +6066,7 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -5546,8 +6077,9 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
setPermsRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -5570,10 +6102,9 @@ setPermsRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
- /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
- data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
+ data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset);
memset(data_offset, 0, count);
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->ParameterOffset = cpu_to_le16(param_offset);
@@ -5587,12 +6118,12 @@ setPermsRetry:
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
cifs_fill_unix_set_info(data_offset, args);
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
@@ -5624,6 +6155,7 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
TRANSACTION2_QPI_RSP *pSMBr = NULL;
int remap = cifs_remap(cifs_sb);
struct nls_table *nls_codepage = cifs_sb->local_nls;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int list_len;
@@ -5638,8 +6170,9 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
QAllEAsRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
list_len =
@@ -5662,7 +6195,7 @@ QAllEAsRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel));
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -5673,10 +6206,10 @@ QAllEAsRetry:
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
@@ -5690,7 +6223,8 @@ QAllEAsRetry:
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || get_bcc(&pSMBr->hdr) < 4) {
- rc = -EIO; /* bad smb */
+ rc = smb_EIO2(smb_eio_trace_qalleas_bcc_too_small,
+ get_bcc(&pSMBr->hdr), 4);
goto QAllEAsOut;
}
@@ -5720,7 +6254,9 @@ QAllEAsRetry:
end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
if ((char *)ea_response_data + list_len > end_of_smb) {
cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_qalleas_overlong,
+ (unsigned long)ea_response_data + list_len - (unsigned long)pSMBr,
+ (unsigned long)end_of_smb - (unsigned long)pSMBr);
goto QAllEAsOut;
}
@@ -5737,7 +6273,7 @@ QAllEAsRetry:
/* make sure we can read name_len and value_len */
if (list_len < 0) {
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_qalleas_ea_overlong, list_len);
goto QAllEAsOut;
}
@@ -5746,7 +6282,7 @@ QAllEAsRetry:
list_len -= name_len + 1 + value_len;
if (list_len < 0) {
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_qalleas_ea_overlong, list_len);
goto QAllEAsOut;
}
@@ -5808,6 +6344,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
struct fealist *parm_data;
+ unsigned int in_len;
int name_len;
int rc = 0;
int bytes_returned = 0;
@@ -5818,8 +6355,9 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
SetEARetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
- if (rc)
+ if (rc < 0)
return rc;
+ in_len = rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
@@ -5851,12 +6389,12 @@ SetEARetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel);
offset = param_offset + params;
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_EA);
- parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
+ parm_data = (void *)pSMB + offset;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->SetupCount = 1;
@@ -5885,9 +6423,9 @@ SetEARetry:
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->Reserved4 = 0;
- inc_rfc1001_len(pSMB, byte_count);
+ in_len += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc)
cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c
index 766b4de13da7..be9023f841e6 100644
--- a/fs/smb/client/compress.c
+++ b/fs/smb/client/compress.c
@@ -44,7 +44,7 @@ struct bucket {
unsigned int count;
};
-/**
+/*
* has_low_entropy() - Compute Shannon entropy of the sampled data.
* @bkt: Bytes counts of the sample.
* @slen: Size of the sample.
@@ -82,7 +82,7 @@ static bool has_low_entropy(struct bucket *bkt, size_t slen)
#define BYTE_DIST_BAD 0
#define BYTE_DIST_GOOD 1
#define BYTE_DIST_MAYBE 2
-/**
+/*
* calc_byte_distribution() - Compute byte distribution on the sampled data.
* @bkt: Byte counts of the sample.
* @slen: Size of the sample.
@@ -155,63 +155,34 @@ static int cmp_bkt(const void *_a, const void *_b)
}
/*
- * TODO:
- * Support other iter types, if required.
- * Only ITER_XARRAY is supported for now.
+ * Collect some 2K samples with 2K gaps between.
*/
-static int collect_sample(const struct iov_iter *iter, ssize_t max, u8 *sample)
+static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
{
- struct folio *folios[16], *folio;
- unsigned int nr, i, j, npages;
- loff_t start = iter->xarray_start + iter->iov_offset;
- pgoff_t last, index = start / PAGE_SIZE;
- size_t len, off, foff;
- void *p;
- int s = 0;
-
- last = (start + max - 1) / PAGE_SIZE;
- do {
- nr = xa_extract(iter->xarray, (void **)folios, index, last, ARRAY_SIZE(folios),
- XA_PRESENT);
- if (nr == 0)
- return -EIO;
-
- for (i = 0; i < nr; i++) {
- folio = folios[i];
- npages = folio_nr_pages(folio);
- foff = start - folio_pos(folio);
- off = foff % PAGE_SIZE;
-
- for (j = foff / PAGE_SIZE; j < npages; j++) {
- size_t len2;
-
- len = min_t(size_t, max, PAGE_SIZE - off);
- len2 = min_t(size_t, len, SZ_2K);
-
- p = kmap_local_page(folio_page(folio, j));
- memcpy(&sample[s], p, len2);
- kunmap_local(p);
-
- s += len2;
-
- if (len2 < SZ_2K || s >= max - SZ_2K)
- return s;
-
- max -= len;
- if (max <= 0)
- return s;
-
- start += len;
- off = 0;
- index++;
- }
- }
- } while (nr == ARRAY_SIZE(folios));
+ struct iov_iter iter = *source;
+ size_t s = 0;
+
+ while (iov_iter_count(&iter) >= SZ_2K) {
+ size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
+ size_t n;
+
+ n = copy_from_iter(sample + s, part, &iter);
+ if (n != part)
+ return -EFAULT;
+
+ s += n;
+ max -= n;
+
+ if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
+ break;
+
+ iov_iter_advance(&iter, SZ_2K);
+ }
return s;
}
-/**
+/*
* is_compressible() - Determines if a chunk of data is compressible.
* @data: Iterator containing uncompressed data.
*
@@ -258,7 +229,7 @@ static bool is_compressible(const struct iov_iter *data)
if (has_repeated_data(sample, len))
goto out;
- bkt = kcalloc(bkt_size, sizeof(*bkt), GFP_KERNEL);
+ bkt = kzalloc_objs(*bkt, bkt_size);
if (!bkt) {
WARN_ON_ONCE(1);
ret = false;
@@ -290,6 +261,21 @@ out:
return ret;
}
+/*
+ * should_compress() - Determines if a request (write) or the response to a
+ * request (read) should be compressed.
+ * @tcon: tcon of the request is being sent to
+ * @rqst: request to evaluate
+ *
+ * Return: true iff:
+ * - compression was successfully negotiated with server
+ * - server has enabled compression for the share
+ * - it's a read or write request
+ * - (write only) request length is >= SMB_COMPRESS_MIN_LEN
+ * - (write only) is_compressible() returns 1
+ *
+ * Return false otherwise.
+ */
bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
{
const struct smb2_hdr *shdr = rq->rq_iov->iov_base;
@@ -339,15 +325,11 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s
iter = rq->rq_iter;
if (!copy_from_iter_full(src, slen, &iter)) {
- ret = -EIO;
+ ret = smb_EIO(smb_eio_trace_compress_copy);
goto err_free;
}
- /*
- * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8
- * of @slen.
- */
- dlen = slen;
+ dlen = lz77_compressed_alloc_size(slen);
dst = kvzalloc(dlen, GFP_KERNEL);
if (!dst) {
ret = -ENOMEM;
diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h
index f3ed1d3e52fb..2679baca129b 100644
--- a/fs/smb/client/compress.h
+++ b/fs/smb/client/compress.h
@@ -29,26 +29,12 @@
#ifdef CONFIG_CIFS_COMPRESSION
typedef int (*compress_send_fn)(struct TCP_Server_Info *, int, struct smb_rqst *);
-int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn);
-/**
- * should_compress() - Determines if a request (write) or the response to a
- * request (read) should be compressed.
- * @tcon: tcon of the request is being sent to
- * @rqst: request to evaluate
- *
- * Return: true iff:
- * - compression was successfully negotiated with server
- * - server has enabled compression for the share
- * - it's a read or write request
- * - (write only) request length is >= SMB_COMPRESS_MIN_LEN
- * - (write only) is_compressible() returns 1
- *
- * Return false otherwise.
- */
+int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq,
+ compress_send_fn send_fn);
bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq);
-/**
+/*
* smb_compress_alg_valid() - Validate a compression algorithm.
* @alg: Compression algorithm to check.
* @valid_none: Conditional check whether NONE algorithm should be
diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c
index 96e8a8057a77..7365d0f97396 100644
--- a/fs/smb/client/compress/lz77.c
+++ b/fs/smb/client/compress/lz77.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2024, SUSE LLC
+ * Copyright (C) 2024-2026, SUSE LLC
*
* Authors: Enzo Matsumiya <ematsumiya@suse.de>
*
@@ -15,19 +15,41 @@
/*
* Compression parameters.
+ *
+ * LZ77_MATCH_MAX_DIST: Farthest back a match can be from current position (can be 1 - 8K).
+ * LZ77_HASH_LOG:
+ * LZ77_HASH_SIZE: ilog2 hash size (recommended to be 13 - 18, default 15 (hash size
+ * 32k)).
+ * LZ77_RSTEP_SIZE: Number of bytes to read from input buffer for hashing and initial
+ * match check (default 4 bytes, this effectivelly makes this the min
+ * match len).
+ * LZ77_MSTEP_SIZE: Number of bytes to extend-compare a found match (default 8 bytes).
+ * LZ77_SKIP_TRIGGER: ilog2 value for adaptive skipping, i.e. to progressively skip input
+ * bytes when we can't find matches. Default is 4.
+ * Higher values (>0) will decrease compression time, but will result
+ * in worse compression ratio. Lower values will give better
+ * compression ratio (more matches found), but will increase time.
*/
-#define LZ77_MATCH_MIN_LEN 4
-#define LZ77_MATCH_MIN_DIST 1
-#define LZ77_MATCH_MAX_DIST SZ_1K
+#define LZ77_MATCH_MAX_DIST SZ_8K
#define LZ77_HASH_LOG 15
#define LZ77_HASH_SIZE (1 << LZ77_HASH_LOG)
-#define LZ77_STEP_SIZE sizeof(u64)
+#define LZ77_RSTEP_SIZE sizeof(u32)
+#define LZ77_MSTEP_SIZE sizeof(u64)
+#define LZ77_SKIP_TRIGGER 4
+
+#define LZ77_PREFETCH(ptr) __builtin_prefetch((ptr), 0, 3)
+#define LZ77_FLAG_MAX 32
static __always_inline u8 lz77_read8(const u8 *ptr)
{
return get_unaligned(ptr);
}
+static __always_inline u32 lz77_read32(const u32 *ptr)
+{
+ return get_unaligned(ptr);
+}
+
static __always_inline u64 lz77_read64(const u64 *ptr)
{
return get_unaligned(ptr);
@@ -48,17 +70,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v)
put_unaligned_le32(v, ptr);
}
-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end)
+static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end)
{
const void *start = cur;
- u64 diff;
/* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */
do {
- diff = lz77_read64(cur) ^ lz77_read64(wnd);
+ const u64 diff = lz77_read64(cur) ^ lz77_read64(match);
+
if (!diff) {
- cur += LZ77_STEP_SIZE;
- wnd += LZ77_STEP_SIZE;
+ cur += LZ77_MSTEP_SIZE;
+ match += LZ77_MSTEP_SIZE;
continue;
}
@@ -67,15 +89,31 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons
cur += count_trailing_zeros(diff) >> 3;
return (cur - start);
- } while (likely(cur + LZ77_STEP_SIZE < end));
+ } while (likely(cur + LZ77_MSTEP_SIZE <= end));
- while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++))
- ;
+ /* Fallback to byte-by-byte comparison for last <8 bytes. */
+ while (cur < end && lz77_read8(cur) == lz77_read8(match)) {
+ cur++;
+ match++;
+ }
return (cur - start);
}
-static __always_inline void *lz77_write_match(void *dst, void **nib, u32 dist, u32 len)
+/**
+ * lz77_encode_match() - Match encoding.
+ * @dst: compressed buffer
+ * @nib: pointer to an address in @dst
+ * @dist: match distance
+ * @len: match length
+ *
+ * Assumes all args were previously checked.
+ *
+ * Return: @dst advanced to new position
+ *
+ * Ref: MS-XCA 2.3.4 "Plain LZ77 Compression Algorithm Details" - "Processing"
+ */
+static __always_inline void *lz77_encode_match(void *dst, void **nib, u16 dist, u32 len)
{
len -= 3;
dist--;
@@ -84,12 +122,12 @@ static __always_inline void *lz77_write_match(void *dst, void **nib, u32 dist, u
if (len < 7) {
lz77_write16(dst, dist + len);
- return dst + 2;
+ return dst + sizeof(u16);
}
dist |= 7;
lz77_write16(dst, dist);
- dst += 2;
+ dst += sizeof(u16);
len -= 7;
if (!*nib) {
@@ -119,113 +157,175 @@ static __always_inline void *lz77_write_match(void *dst, void **nib, u32 dist, u
if (len <= 0xffff) {
lz77_write16(dst, len);
- return dst + 2;
+ return dst + sizeof(u16);
}
lz77_write16(dst, 0);
- dst += 2;
+ dst += sizeof(u16);
lz77_write32(dst, len);
- return dst + 4;
+ return dst + sizeof(u32);
+}
+
+/**
+ * lz77_encode_literals() - Literals encoding.
+ * @start: where to start copying literals (uncompressed buffer)
+ * @end: when to stop copying (uncompressed buffer)
+ * @dst: compressed buffer
+ * @f: pointer to current flag value
+ * @fc: pointer to current flag count
+ * @fp: pointer to current flag address
+ *
+ * Batch copy literals from @start to @dst, updating flag values accordingly.
+ * Assumes all args were previously checked.
+ *
+ * Return: @dst advanced to new position
+ *
+ * MS-XCA 2.3.4 "Plain LZ77 Compression Algorithm Details" - "Processing"
+ */
+static __always_inline void *lz77_encode_literals(const void *start, const void *end, void *dst,
+ long *f, u32 *fc, void **fp)
+{
+ if (start >= end)
+ return dst;
+
+ do {
+ const u32 len = umin(end - start, LZ77_FLAG_MAX - *fc);
+
+ memcpy(dst, start, len);
+
+ dst += len;
+ start += len;
+
+ *f <<= len;
+ *fc += len;
+ if (*fc == LZ77_FLAG_MAX) {
+ lz77_write32(*fp, *f);
+ *fc = 0;
+ *fp = dst;
+ dst += sizeof(u32);
+ }
+ } while (start < end);
+
+ return dst;
}
-noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen)
+static __always_inline u32 lz77_hash(const u32 v)
{
- const void *srcp, *end;
+ return ((v ^ 0x9E3779B9) * 0x85EBCA6B) >> (32 - LZ77_HASH_LOG);
+}
+
+noinline int lz77_compress(const void *src, const u32 slen, void *dst, u32 *dlen)
+{
+ const void *srcp, *rlim, *end, *anchor;
+ u32 *htable, hash, flag_count = 0;
void *dstp, *nib, *flag_pos;
- u32 flag_count = 0;
long flag = 0;
- u64 *htable;
- srcp = src;
- end = src + slen;
+ /* This is probably a bug, so throw a warning. */
+ if (WARN_ON_ONCE(*dlen < lz77_compressed_alloc_size(slen)))
+ return -EINVAL;
+
+ srcp = anchor = src;
+ end = srcp + slen; /* absolute end */
+ rlim = end - LZ77_MSTEP_SIZE; /* read limit (for lz77_match_len()) */
dstp = dst;
- nib = NULL;
flag_pos = dstp;
- dstp += 4;
+ dstp += sizeof(u32);
+ nib = NULL;
htable = kvcalloc(LZ77_HASH_SIZE, sizeof(*htable), GFP_KERNEL);
if (!htable)
return -ENOMEM;
- /* Main loop. */
+ LZ77_PREFETCH(srcp + LZ77_RSTEP_SIZE);
+
+ /*
+ * Adjust @srcp so we don't get a false positive match on first iteration.
+ * Then prepare hash for first loop iteration (don't advance @srcp again).
+ */
+ hash = lz77_hash(lz77_read32(srcp++));
+ htable[hash] = 0;
+ hash = lz77_hash(lz77_read32(srcp));
+
+ /*
+ * Main loop.
+ *
+ * @dlen is >= lz77_compressed_alloc_size(), so run without bound-checking @dstp.
+ *
+ * This code was crafted in a way to best utilise fetch-decode-execute CPU flow.
+ * Any attempt to optimize it, or even organize it, can lead to huge performance loss.
+ */
do {
- u32 dist, len = 0;
- const void *wnd;
- u64 hash;
-
- hash = ((lz77_read64(srcp) << 24) * 889523592379ULL) >> (64 - LZ77_HASH_LOG);
- wnd = src + htable[hash];
- htable[hash] = srcp - src;
- dist = srcp - wnd;
-
- if (dist && dist < LZ77_MATCH_MAX_DIST)
- len = lz77_match_len(wnd, srcp, end);
-
- if (len < LZ77_MATCH_MIN_LEN) {
- lz77_write8(dstp, lz77_read8(srcp));
-
- dstp++;
- srcp++;
-
- flag <<= 1;
- flag_count++;
- if (flag_count == 32) {
- lz77_write32(flag_pos, flag);
- flag_count = 0;
- flag_pos = dstp;
- dstp += 4;
- }
-
- continue;
- }
+ const void *match, *next = srcp;
+ u32 len, step = 1, skip = 1U << LZ77_SKIP_TRIGGER;
+
+ /* Match finding (hot path -- don't change the read/check/write order). */
+ do {
+ const u32 cur_hash = hash;
+
+ srcp = next;
+ next += step;
+
+ /*
+ * Adaptive skipping.
+ *
+ * Increment @step every (1 << LZ77_SKIP_TRIGGER, 16 in our case) bytes
+ * without a match.
+ * Reset to 1 when a match is found.
+ */
+ step = (skip++ >> LZ77_SKIP_TRIGGER);
+ if (unlikely(next > rlim))
+ goto out;
+
+ hash = lz77_hash(lz77_read32(next));
+ match = src + htable[cur_hash];
+ htable[cur_hash] = srcp - src;
+ } while (likely(match + LZ77_MATCH_MAX_DIST < srcp) ||
+ lz77_read32(match) != lz77_read32(srcp));
/*
- * Bail out if @dstp reached >= 7/8 of @slen -- already compressed badly, not worth
- * going further.
+ * Match found. Warm/cold path; begin parsing @srcp and writing to @dstp:
+ * - flush literals
+ * - compute match length (*)
+ * - encode match
+ *
+ * (*) Current minimum match length is defined by the memory read size above, so
+ * here we already know that we have 4 matching bytes, but it's just faster to
+ * redundantly compute it again in lz77_match_len() than to adjust pointers/len.
*/
- if (unlikely(dstp - dst >= slen - (slen >> 3))) {
- *dlen = slen;
- goto out;
- }
-
- dstp = lz77_write_match(dstp, &nib, dist, len);
+ dstp = lz77_encode_literals(anchor, srcp, dstp, &flag, &flag_count, &flag_pos);
+ len = lz77_match_len(match, srcp, end);
+ dstp = lz77_encode_match(dstp, &nib, srcp - match, len);
srcp += len;
+ anchor = srcp;
+
+ LZ77_PREFETCH(srcp);
flag = (flag << 1) | 1;
flag_count++;
- if (flag_count == 32) {
+ if (flag_count == LZ77_FLAG_MAX) {
lz77_write32(flag_pos, flag);
flag_count = 0;
flag_pos = dstp;
- dstp += 4;
+ dstp += sizeof(u32);
}
- } while (likely(srcp + LZ77_STEP_SIZE < end));
- while (srcp < end) {
- u32 c = umin(end - srcp, 32 - flag_count);
+ if (unlikely(srcp > rlim))
+ break;
- memcpy(dstp, srcp, c);
-
- dstp += c;
- srcp += c;
-
- flag <<= c;
- flag_count += c;
- if (flag_count == 32) {
- lz77_write32(flag_pos, flag);
- flag_count = 0;
- flag_pos = dstp;
- dstp += 4;
- }
- }
+ /* Prepare for next loop. */
+ hash = lz77_hash(lz77_read32(srcp));
+ } while (srcp < end);
+out:
+ dstp = lz77_encode_literals(anchor, end, dstp, &flag, &flag_count, &flag_pos);
- flag <<= (32 - flag_count);
- flag |= (1 << (32 - flag_count)) - 1;
+ flag_count = LZ77_FLAG_MAX - flag_count;
+ flag <<= flag_count;
+ flag |= (1UL << flag_count) - 1;
lz77_write32(flag_pos, flag);
*dlen = dstp - dst;
-out:
kvfree(htable);
if (*dlen < slen)
diff --git a/fs/smb/client/compress/lz77.h b/fs/smb/client/compress/lz77.h
index cdcb191b48a2..4e570846aefa 100644
--- a/fs/smb/client/compress/lz77.h
+++ b/fs/smb/client/compress/lz77.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2024, SUSE LLC
+ * Copyright (C) 2024-2026, SUSE LLC
*
* Authors: Enzo Matsumiya <ematsumiya@suse.de>
*
@@ -11,5 +11,33 @@
#include <linux/kernel.h>
-int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen);
+/**
+ * lz77_compressed_alloc_size() - Compute compressed buffer size.
+ * @size: uncompressed (src) size
+ *
+ * Compute allocation size for the compressed buffer based on uncompressed size.
+ * Accounts for metadata and overprovision for the worst case scenario.
+ *
+ * LZ77 metadata is a 4-byte flag that is written:
+ * - on dst begin (pos 0)
+ * - every 32 literals or matches
+ * - on end-of-stream (possibly, if last write was another flag)
+ *
+ * Worst case scenario is an all-literal compression, which means:
+ * metadata bytes = 4 + ((@size / 32) * 4) + 4, or, simplified, (@size >> 3) + 8
+ *
+ * The worst case scenario rarely happens, but such overprovisioning also allows lz77_compress()
+ * main loop to run without ever bound checking dst, which is a huge perf improvement, while also
+ * being safe when compression goes bad.
+ *
+ * Return: required (*) allocation size for compressed buffer.
+ *
+ * (*) checked once in the beginning of lz77_compress()
+ */
+static __always_inline u32 lz77_compressed_alloc_size(const u32 size)
+{
+ return size + (size >> 3) + 8;
+}
+
+int lz77_compress(const void *src, const u32 slen, void *dst, u32 *dlen);
#endif /* _SMB_COMPRESS_LZ77_H */
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index df976ce6aed9..dcde25da468d 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -20,7 +20,6 @@
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/kthread.h>
-#include <linux/pagevec.h>
#include <linux/freezer.h>
#include <linux/namei.h>
#include <linux/uuid.h>
@@ -32,7 +31,6 @@
#include <net/ipv6.h>
#include <linux/parser.h>
#include <linux/bvec.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
@@ -64,6 +62,10 @@ static int generic_ip_connect(struct TCP_Server_Info *server);
static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
static void cifs_prune_tlinks(struct work_struct *work);
+static struct mchan_mount *mchan_mount_alloc(struct cifs_ses *ses);
+static void mchan_mount_free(struct mchan_mount *mchan_mount);
+static void mchan_mount_work_fn(struct work_struct *work);
+
/*
* Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
* get their ip addresses changed at some point.
@@ -97,7 +99,7 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
return rc;
}
-static void smb2_query_server_interfaces(struct work_struct *work)
+void smb2_query_server_interfaces(struct work_struct *work)
{
int rc;
int xid;
@@ -116,18 +118,22 @@ static void smb2_query_server_interfaces(struct work_struct *work)
rc = server->ops->query_server_interfaces(xid, tcon, false);
free_xid(xid);
- if (rc) {
- if (rc == -EOPNOTSUPP)
- return;
-
+ if (rc)
cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
__func__, rc);
- }
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
(SMB_INTERFACE_POLL_INTERVAL * HZ));
}
+#define set_need_reco(server) \
+do { \
+ spin_lock(&server->srv_lock); \
+ if (server->tcpStatus != CifsExiting) \
+ server->tcpStatus = CifsNeedReconnect; \
+ spin_unlock(&server->srv_lock); \
+} while (0)
+
/*
* Update the tcpStatus for the server.
* This is used to signal the cifsd thread to call cifs_reconnect
@@ -141,39 +147,45 @@ void
cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
bool all_channels)
{
- struct TCP_Server_Info *pserver;
+ struct TCP_Server_Info *nserver;
struct cifs_ses *ses;
+ LIST_HEAD(reco);
int i;
- /* If server is a channel, select the primary channel */
- pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
-
/* if we need to signal just this channel */
if (!all_channels) {
- spin_lock(&server->srv_lock);
- if (server->tcpStatus != CifsExiting)
- server->tcpStatus = CifsNeedReconnect;
- spin_unlock(&server->srv_lock);
+ set_need_reco(server);
return;
}
- spin_lock(&cifs_tcp_ses_lock);
- list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
- if (cifs_ses_exiting(ses))
- continue;
- spin_lock(&ses->chan_lock);
- for (i = 0; i < ses->chan_count; i++) {
- if (!ses->chans[i].server)
+ if (SERVER_IS_CHAN(server))
+ server = server->primary_server;
+ scoped_guard(spinlock, &cifs_tcp_ses_lock) {
+ set_need_reco(server);
+ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+ spin_lock(&ses->ses_lock);
+ if (ses->ses_status == SES_EXITING) {
+ spin_unlock(&ses->ses_lock);
continue;
-
- spin_lock(&ses->chans[i].server->srv_lock);
- if (ses->chans[i].server->tcpStatus != CifsExiting)
- ses->chans[i].server->tcpStatus = CifsNeedReconnect;
- spin_unlock(&ses->chans[i].server->srv_lock);
+ }
+ spin_lock(&ses->chan_lock);
+ for (i = 1; i < ses->chan_count; i++) {
+ nserver = ses->chans[i].server;
+ if (!nserver)
+ continue;
+ nserver->srv_count++;
+ list_add(&nserver->rlist, &reco);
+ }
+ spin_unlock(&ses->chan_lock);
+ spin_unlock(&ses->ses_lock);
}
- spin_unlock(&ses->chan_lock);
}
- spin_unlock(&cifs_tcp_ses_lock);
+
+ list_for_each_entry_safe(server, nserver, &reco, rlist) {
+ list_del_init(&server->rlist);
+ set_need_reco(server);
+ cifs_put_tcp_session(server, 0);
+ }
}
/*
@@ -300,6 +312,8 @@ cifs_abort_connection(struct TCP_Server_Info *server)
server->ssocket->flags);
sock_release(server->ssocket);
server->ssocket = NULL;
+ } else if (cifs_rdma_enabled(server)) {
+ smbd_destroy(server);
}
server->sequence_number = 0;
server->session_estab = false;
@@ -311,28 +325,22 @@ cifs_abort_connection(struct TCP_Server_Info *server)
/* mark submitted MIDs for retry and issue callback */
INIT_LIST_HEAD(&retry_list);
cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
- kref_get(&mid->refcount);
+ smb_get_mid(mid);
if (mid->mid_state == MID_REQUEST_SUBMITTED)
mid->mid_state = MID_RETRY_NEEDED;
list_move(&mid->qhead, &retry_list);
- mid->mid_flags |= MID_DELETED;
+ mid->deleted_from_q = true;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
cifs_server_unlock(server);
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
list_for_each_entry_safe(mid, nmid, &retry_list, qhead) {
list_del_init(&mid->qhead);
- mid->callback(mid);
- release_mid(mid);
- }
-
- if (cifs_rdma_enabled(server)) {
- cifs_server_lock(server);
- smbd_destroy(server);
- cifs_server_unlock(server);
+ mid_execute_callback(server, mid);
+ release_mid(server, mid);
}
}
@@ -348,7 +356,7 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num
}
cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
- trace_smb3_reconnect(server->CurrentMid, server->conn_id,
+ trace_smb3_reconnect(server->current_mid, server->conn_id,
server->hostname);
server->tcpStatus = CifsNeedReconnect;
@@ -377,6 +385,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
if (!cifs_tcp_ses_needs_reconnect(server, 1))
return 0;
+ /*
+ * if smb session has been marked for reconnect, also reconnect all
+ * connections. This way, the other connections do not end up bad.
+ */
+ if (mark_smb_session)
+ cifs_signal_cifsd_for_reconnect(server, mark_smb_session);
+
cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
cifs_abort_connection(server);
@@ -385,7 +400,8 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
try_to_freeze();
cifs_server_lock(server);
- if (!cifs_swn_set_server_dstaddr(server)) {
+ if (!cifs_swn_set_server_dstaddr(server) &&
+ !SERVER_IS_CHAN(server)) {
/* resolve the hostname again to make sure that IP address is up-to-date */
rc = reconn_set_ipaddr_from_hostname(server);
cifs_dbg(FYI, "%s: reconn_set_ipaddr_from_hostname: rc=%d\n", __func__, rc);
@@ -411,7 +427,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
spin_unlock(&server->srv_lock);
cifs_swn_reset_server_dstaddr(server);
cifs_server_unlock(server);
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ cifs_queue_server_reconn(server);
}
} while (server->tcpStatus == CifsNeedReconnect);
@@ -550,7 +566,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
spin_unlock(&server->srv_lock);
cifs_swn_reset_server_dstaddr(server);
cifs_server_unlock(server);
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ cifs_queue_server_reconn(server);
} while (server->tcpStatus == CifsNeedReconnect);
dfs_cache_noreq_update_tgthint(ref_path, target_hint);
@@ -661,12 +677,12 @@ server_unresponsive(struct TCP_Server_Info *server)
/*
* If we're in the process of mounting a share or reconnecting a session
* and the server abruptly shut down (e.g. socket wasn't closed, packet
- * had been ACK'ed but no SMB response), don't wait longer than 20s to
- * negotiate protocol.
+ * had been ACK'ed but no SMB response), don't wait longer than 20s from
+ * when negotiate actually started.
*/
spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsInNegotiate &&
- time_after(jiffies, server->lstrp + 20 * HZ)) {
+ time_after(jiffies, server->neg_start + 20 * HZ)) {
spin_unlock(&server->srv_lock);
cifs_reconnect(server, false);
return true;
@@ -866,13 +882,13 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
* server there should be exactly one pending mid
* corresponding to SMB1/SMB2 Negotiate packet.
*/
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
- kref_get(&mid->refcount);
+ smb_get_mid(mid);
list_move(&mid->qhead, &dispose_list);
- mid->mid_flags |= MID_DELETED;
+ mid->deleted_from_q = true;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
/* Now try to reconnect once with NetBIOS session. */
server->with_rfc1001 = true;
@@ -901,8 +917,8 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
list_del_init(&mid->qhead);
mid->mid_rc = mid_rc;
mid->mid_state = MID_RC;
- mid->callback(mid);
- release_mid(mid);
+ mid_execute_callback(server, mid);
+ release_mid(server, mid);
}
/*
@@ -934,12 +950,12 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
}
void
-dequeue_mid(struct mid_q_entry *mid, bool malformed)
+dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid, bool malformed)
{
#ifdef CONFIG_CIFS_STATS2
mid->when_received = jiffies;
#endif
- spin_lock(&mid->server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
if (!malformed)
mid->mid_state = MID_RESPONSE_RECEIVED;
else
@@ -948,13 +964,13 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
* Trying to handle/dequeue a mid after the send_recv()
* function has finished processing it is a bug.
*/
- if (mid->mid_flags & MID_DELETED) {
- spin_unlock(&mid->server->mid_lock);
+ if (mid->deleted_from_q == true) {
+ spin_unlock(&server->mid_queue_lock);
pr_warn_once("trying to dequeue a deleted mid\n");
} else {
list_del_init(&mid->qhead);
- mid->mid_flags |= MID_DELETED;
- spin_unlock(&mid->server->mid_lock);
+ mid->deleted_from_q = true;
+ spin_unlock(&server->mid_queue_lock);
}
}
@@ -990,7 +1006,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
else
server->smallbuf = NULL;
}
- dequeue_mid(mid, malformed);
+ dequeue_mid(server, mid, malformed);
}
int
@@ -1083,24 +1099,24 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
struct list_head *tmp, *tmp2;
LIST_HEAD(dispose_list);
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
- kref_get(&mid_entry->refcount);
+ smb_get_mid(mid_entry);
mid_entry->mid_state = MID_SHUTDOWN;
list_move(&mid_entry->qhead, &dispose_list);
- mid_entry->mid_flags |= MID_DELETED;
+ mid_entry->deleted_from_q = true;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
/* now walk dispose list and issue callbacks */
list_for_each_safe(tmp, tmp2, &dispose_list) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
list_del_init(&mid_entry->qhead);
- mid_entry->callback(mid_entry);
- release_mid(mid_entry);
+ mid_execute_callback(server, mid_entry);
+ release_mid(server, mid_entry);
}
/* 1/8th of sec is more than enough time for them to exit */
msleep(125);
@@ -1141,15 +1157,14 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
unsigned int pdu_length = server->pdu_size;
/* make sure this will fit in a large buffer */
- if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
- HEADER_PREAMBLE_SIZE(server)) {
+ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
cifs_reconnect(server, true);
return -ECONNABORTED;
}
/* switch to large buffer if too big for a small one */
- if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
+ if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
server->large_buf = true;
memcpy(server->bigbuf, buf, server->total_read);
buf = server->bigbuf;
@@ -1182,7 +1197,8 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
* 48 bytes is enough to display the header and a little bit
* into the payload for debugging purposes.
*/
- rc = server->ops->check_message(buf, server->total_read, server);
+ rc = server->ops->check_message(buf, server->pdu_size,
+ server->total_read, server);
if (rc)
cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, server->total_read, 48));
@@ -1224,7 +1240,7 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
- trace_smb3_hdr_credits(server->CurrentMid,
+ trace_smb3_hdr_credits(server->current_mid,
server->conn_id, server->hostname, scredits,
le16_to_cpu(shdr->CreditRequest), in_flight);
cifs_server_dbg(FYI, "%s: added %u credits total=%d\n",
@@ -1272,16 +1288,13 @@ cifs_demultiplex_thread(void *p)
if (length < 0)
continue;
- if (is_smb1(server))
- server->total_read = length;
- else
- server->total_read = 0;
+ server->total_read = 0;
/*
* The right amount was read from socket - 4 bytes,
* so we can now interpret the length field.
*/
- pdu_length = get_rfc1002_length(buf);
+ pdu_length = be32_to_cpup(((__be32 *)buf)) & 0xffffff;
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
if (!is_smb_response(server, buf[0]))
@@ -1300,9 +1313,8 @@ next_pdu:
}
/* read down to the MID */
- length = cifs_read_from_socket(server,
- buf + HEADER_PREAMBLE_SIZE(server),
- MID_HEADER_SIZE(server));
+ length = cifs_read_from_socket(server, buf,
+ MID_HEADER_SIZE(server));
if (length < 0)
continue;
server->total_read += length;
@@ -1334,6 +1346,8 @@ next_pdu:
bufs[0] = buf;
num_mids = 1;
+ if (mids[0])
+ mids[0]->response_pdu_len = pdu_length;
if (!mids[0] || !mids[0]->receive)
length = standard_receive3(server, mids[0]);
else
@@ -1343,7 +1357,7 @@ next_pdu:
if (length < 0) {
for (i = 0; i < num_mids; i++)
if (mids[i])
- release_mid(mids[i]);
+ release_mid(server, mids[i]);
continue;
}
@@ -1376,9 +1390,9 @@ next_pdu:
}
if (!mids[i]->multiRsp || mids[i]->multiEnd)
- mids[i]->callback(mids[i]);
+ mid_execute_callback(server, mids[i]);
- release_mid(mids[i]);
+ release_mid(server, mids[i]);
} else if (server->ops->is_oplock_break &&
server->ops->is_oplock_break(bufs[i],
server)) {
@@ -1392,7 +1406,7 @@ next_pdu:
smb2_add_credits_from_hdr(bufs[i], server);
#ifdef CONFIG_CIFS_DEBUG2
if (server->ops->dump_detail)
- server->ops->dump_detail(bufs[i],
+ server->ops->dump_detail(bufs[i], pdu_length,
server);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
@@ -1740,7 +1754,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
if (tcp_ses)
return tcp_ses;
- tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
+ tcp_ses = kzalloc_obj(struct TCP_Server_Info);
if (!tcp_ses) {
rc = -ENOMEM;
goto out_err;
@@ -1804,7 +1818,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
tcp_ses->compression.requested = ctx->compress;
spin_lock_init(&tcp_ses->req_lock);
spin_lock_init(&tcp_ses->srv_lock);
- spin_lock_init(&tcp_ses->mid_lock);
+ spin_lock_init(&tcp_ses->mid_queue_lock);
+ spin_lock_init(&tcp_ses->mid_counter_lock);
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
@@ -1939,6 +1954,10 @@ static int match_session(struct cifs_ses *ses,
case Kerberos:
if (!uid_eq(ctx->cred_uid, ses->cred_uid))
return 0;
+ if (strncmp(ses->user_name ?: "",
+ ctx->username ?: "",
+ CIFS_MAX_USERNAME_LEN))
+ return 0;
break;
case NTLMv2:
case RawNTLMSSP:
@@ -1996,39 +2015,31 @@ static int match_session(struct cifs_ses *ses,
/**
* cifs_setup_ipc - helper to setup the IPC tcon for the session
* @ses: smb session to issue the request on
- * @ctx: the superblock configuration context to use for building the
- * new tree connection for the IPC (interprocess communication RPC)
+ * @seal: if encryption is requested
*
* A new IPC connection is made and stored in the session
* tcon_ipc. The IPC tcon has the same lifetime as the session.
*/
-static int
-cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
+struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
{
int rc = 0, xid;
struct cifs_tcon *tcon;
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
- bool seal = false;
struct TCP_Server_Info *server = ses->server;
/*
* If the mount request that resulted in the creation of the
* session requires encryption, force IPC to be encrypted too.
*/
- if (ctx->seal) {
- if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
- seal = true;
- else {
- cifs_server_dbg(VFS,
- "IPC: server doesn't support encryption\n");
- return -EOPNOTSUPP;
- }
+ if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
+ cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
+ return ERR_PTR(-EOPNOTSUPP);
}
/* no need to setup directory caching on IPC share, so pass in false */
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
if (tcon == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
spin_lock(&server->srv_lock);
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
@@ -2038,13 +2049,13 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
tcon->ses = ses;
tcon->ipc = true;
tcon->seal = seal;
- rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
+ rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
free_xid(xid);
if (rc) {
- cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
+ cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
- goto out;
+ return ERR_PTR(rc);
}
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
@@ -2052,9 +2063,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
spin_lock(&tcon->tc_lock);
tcon->status = TID_GOOD;
spin_unlock(&tcon->tc_lock);
- ses->tcon_ipc = tcon;
-out:
- return rc;
+ return tcon;
}
static struct cifs_ses *
@@ -2161,9 +2170,6 @@ void __cifs_put_smb_ses(struct cifs_ses *ses)
#ifdef CONFIG_KEYS
-/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
-#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
-
/* Populate username and pw fields from keyring if possible */
static int
cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
@@ -2171,6 +2177,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
int rc = 0;
int is_domain = 0;
const char *delim, *payload;
+ size_t desc_sz;
char *desc;
ssize_t len;
struct key *key;
@@ -2179,7 +2186,9 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
struct sockaddr_in6 *sa6;
const struct user_key_payload *upayload;
- desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
+ /* "cifs:a:" and "cifs:d:" are the same length; +1 for NUL terminator */
+ desc_sz = strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1;
+ desc = kmalloc(desc_sz, GFP_KERNEL);
if (!desc)
return -ENOMEM;
@@ -2187,11 +2196,11 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
switch (server->dstaddr.ss_family) {
case AF_INET:
sa = (struct sockaddr_in *)&server->dstaddr;
- sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
+ snprintf(desc, desc_sz, "cifs:a:%pI4", &sa->sin_addr.s_addr);
break;
case AF_INET6:
sa6 = (struct sockaddr_in6 *)&server->dstaddr;
- sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
+ snprintf(desc, desc_sz, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
break;
default:
cifs_dbg(FYI, "Bad ss_family (%hu)\n",
@@ -2210,7 +2219,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
}
/* didn't work, try to find a domain key */
- sprintf(desc, "cifs:d:%s", ses->domainName);
+ snprintf(desc, desc_sz, "cifs:d:%s", ses->domainName);
cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
key = request_key(&key_type_logon, desc, "");
if (IS_ERR(key)) {
@@ -2230,7 +2239,6 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
/* find first : in payload */
payload = upayload->data;
delim = strnchr(payload, upayload->datalen, ':');
- cifs_dbg(FYI, "payload=%s\n", payload);
if (!delim) {
cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
upayload->datalen);
@@ -2307,8 +2315,8 @@ out_err:
}
#else /* ! CONFIG_KEYS */
static inline int
-cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)),
- struct cifs_ses *ses __attribute__((unused)))
+cifs_set_cifscreds(struct smb3_fs_context *ctx __maybe_unused,
+ struct cifs_ses *ses __maybe_unused)
{
return -ENOSYS;
}
@@ -2328,6 +2336,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
{
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
+ struct cifs_tcon *ipc;
struct cifs_ses *ses;
unsigned int xid;
int retries = 0;
@@ -2506,7 +2515,12 @@ retry_new_session:
list_add(&ses->smb_ses_list, &server->smb_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
- cifs_setup_ipc(ses, ctx);
+ ipc = cifs_setup_ipc(ses, ctx->seal);
+ spin_lock(&cifs_tcp_ses_lock);
+ spin_lock(&ses->ses_lock);
+ ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
+ spin_unlock(&ses->ses_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
free_xid(xid);
@@ -2862,20 +2876,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
tcon->max_cached_dirs = ctx->max_cached_dirs;
tcon->nodelete = ctx->nodelete;
tcon->local_lease = ctx->local_lease;
- INIT_LIST_HEAD(&tcon->pending_opens);
tcon->status = TID_GOOD;
- INIT_DELAYED_WORK(&tcon->query_interfaces,
- smb2_query_server_interfaces);
if (ses->server->dialect >= SMB30_PROT_ID &&
(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
/* schedule query interfaces poll */
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
(SMB_INTERFACE_POLL_INTERVAL * HZ));
}
-#ifdef CONFIG_CIFS_DFS_UPCALL
- INIT_DELAYED_WORK(&tcon->dfs_cache_work, dfs_cache_refresh);
-#endif
spin_lock(&cifs_tcp_ses_lock);
list_add(&tcon->tcon_list, &ses->tcon_list);
spin_unlock(&cifs_tcp_ses_lock);
@@ -2909,8 +2917,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
{
struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb;
- unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
- unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
+ unsigned int oldflags = cifs_sb_flags(old) & CIFS_MOUNT_MASK;
+ unsigned int newflags = cifs_sb_flags(new) & CIFS_MOUNT_MASK;
if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
return 0;
@@ -2965,9 +2973,9 @@ static int match_prepath(struct super_block *sb,
struct smb3_fs_context *ctx = mnt_data->ctx;
struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb;
- bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ bool old_set = (cifs_sb_flags(old) & CIFS_MOUNT_USE_PREFIX_PATH) &&
old->prepath;
- bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ bool new_set = (cifs_sb_flags(new) & CIFS_MOUNT_USE_PREFIX_PATH) &&
new->prepath;
if (tcon->origin_fullpath &&
@@ -2998,7 +3006,7 @@ cifs_match_super(struct super_block *sb, void *data)
cifs_sb = CIFS_SB(sb);
/* We do not want to use a superblock that has been shutdown */
- if (CIFS_MOUNT_SHUTDOWN & cifs_sb->mnt_cifs_flags) {
+ if (cifs_forced_shutdown(cifs_sb)) {
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
@@ -3099,7 +3107,7 @@ bind_socket(struct TCP_Server_Info *server)
struct socket *socket = server->ssocket;
rc = kernel_bind(socket,
- (struct sockaddr *) &server->srcaddr,
+ (struct sockaddr_unsized *) &server->srcaddr,
sizeof(server->srcaddr));
if (rc < 0) {
struct sockaddr_in *saddr4;
@@ -3237,7 +3245,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
if (be16_to_cpu(resp.length) != 0) {
cifs_dbg(VFS, "RFC 1002 positive session response but with invalid non-zero length %u\n",
be16_to_cpu(resp.length));
- return -EIO;
+ return smb_EIO(smb_eio_trace_rx_pos_sess_resp);
}
cifs_dbg(FYI, "RFC 1002 positive session response");
break;
@@ -3276,17 +3284,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
break;
case RFC1002_INSUFFICIENT_RESOURCE:
/* remote server resource error */
+ smb_EIO(smb_eio_trace_rx_insuff_res);
rc = -EREMOTEIO;
break;
case RFC1002_UNSPECIFIED_ERROR:
default:
/* other/unknown error */
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_rx_unspec_error);
break;
}
} else {
cifs_dbg(VFS, "RFC 1002 negative session response\n");
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_rx_neg_sess_resp);
}
return rc;
case RFC1002_RETARGET_SESSION_RESPONSE:
@@ -3308,7 +3317,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
return -EMULTIHOP;
default:
cifs_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", resp.type);
- return -EIO;
+ return smb_EIO1(smb_eio_trace_rx_unknown_resp, resp.type);
}
server->with_rfc1001 = true;
@@ -3350,18 +3359,15 @@ generic_ip_connect(struct TCP_Server_Info *server)
struct net *net = cifs_net_ns(server);
struct sock *sk;
- rc = __sock_create(net, sfamily, SOCK_STREAM,
- IPPROTO_TCP, &server->ssocket, 1);
+ rc = sock_create_kern(net, sfamily, SOCK_STREAM,
+ IPPROTO_TCP, &server->ssocket);
if (rc < 0) {
cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
return rc;
}
sk = server->ssocket->sk;
- __netns_tracker_free(net, &sk->ns_tracker, false);
- sk->sk_net_refcnt = 1;
- get_net_track(net, &sk->ns_tracker, GFP_KERNEL);
- sock_inuse_add(net, 1);
+ sk_net_refcnt_upgrade(sk);
/* BB other socket options to set KEEPALIVE, NODELAY? */
cifs_dbg(FYI, "Socket created\n");
@@ -3401,7 +3407,7 @@ generic_ip_connect(struct TCP_Server_Info *server)
socket->sk->sk_sndbuf,
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
- rc = kernel_connect(socket, saddr, slen,
+ rc = kernel_connect(socket, (struct sockaddr_unsized *)saddr, slen,
server->noblockcnt ? O_NONBLOCK : 0);
/*
* When mounting SMB root file systems, we do not want to block in
@@ -3462,118 +3468,11 @@ ip_connect(struct TCP_Server_Info *server)
return generic_ip_connect(server);
}
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
-{
- /*
- * If we are reconnecting then should we check to see if
- * any requested capabilities changed locally e.g. via
- * remount but we can not do much about it here
- * if they have (even if we could detect it by the following)
- * Perhaps we could add a backpointer to array of sb from tcon
- * or if we change to make all sb to same share the same
- * sb as NFS - then we only have one backpointer to sb.
- * What if we wanted to mount the server share twice once with
- * and once without posixacls or posix paths?
- */
- __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-
- if (ctx && ctx->no_linux_ext) {
- tcon->fsUnixInfo.Capability = 0;
- tcon->unix_ext = 0; /* Unix Extensions disabled */
- cifs_dbg(FYI, "Linux protocol extensions disabled\n");
- return;
- } else if (ctx)
- tcon->unix_ext = 1; /* Unix Extensions supported */
-
- if (!tcon->unix_ext) {
- cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
- return;
- }
-
- if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
- __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-
- cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
- /*
- * check for reconnect case in which we do not
- * want to change the mount behavior if we can avoid it
- */
- if (ctx == NULL) {
- /*
- * turn off POSIX ACL and PATHNAMES if not set
- * originally at mount time
- */
- if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
- cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
- if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
- if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
- cifs_dbg(VFS, "POSIXPATH support change\n");
- cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
- } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
- cifs_dbg(VFS, "possible reconnect error\n");
- cifs_dbg(VFS, "server disabled POSIX path support\n");
- }
- }
-
- if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
- cifs_dbg(VFS, "per-share encryption not supported yet\n");
-
- cap &= CIFS_UNIX_CAP_MASK;
- if (ctx && ctx->no_psx_acl)
- cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
- else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
- cifs_dbg(FYI, "negotiated posix acl support\n");
- if (cifs_sb)
- cifs_sb->mnt_cifs_flags |=
- CIFS_MOUNT_POSIXACL;
- }
-
- if (ctx && ctx->posix_paths == 0)
- cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
- else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
- cifs_dbg(FYI, "negotiate posix pathnames\n");
- if (cifs_sb)
- cifs_sb->mnt_cifs_flags |=
- CIFS_MOUNT_POSIX_PATHS;
- }
-
- cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
-#ifdef CONFIG_CIFS_DEBUG2
- if (cap & CIFS_UNIX_FCNTL_CAP)
- cifs_dbg(FYI, "FCNTL cap\n");
- if (cap & CIFS_UNIX_EXTATTR_CAP)
- cifs_dbg(FYI, "EXTATTR cap\n");
- if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
- cifs_dbg(FYI, "POSIX path cap\n");
- if (cap & CIFS_UNIX_XATTR_CAP)
- cifs_dbg(FYI, "XATTR cap\n");
- if (cap & CIFS_UNIX_POSIX_ACL_CAP)
- cifs_dbg(FYI, "POSIX ACL cap\n");
- if (cap & CIFS_UNIX_LARGE_READ_CAP)
- cifs_dbg(FYI, "very large read cap\n");
- if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
- cifs_dbg(FYI, "very large write cap\n");
- if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
- cifs_dbg(FYI, "transport encryption cap\n");
- if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
- cifs_dbg(FYI, "mandatory transport encryption cap\n");
-#endif /* CIFS_DEBUG2 */
- if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
- if (ctx == NULL)
- cifs_dbg(FYI, "resetting capabilities failed\n");
- else
- cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n");
-
- }
- }
-}
-#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
-
int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
{
struct smb3_fs_context *ctx = cifs_sb->ctx;
+ unsigned int sbflags;
+ int rc = 0;
INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
INIT_LIST_HEAD(&cifs_sb->tcon_sb_link);
@@ -3598,17 +3497,16 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
}
ctx->local_nls = cifs_sb->local_nls;
- smb3_update_mnt_flags(cifs_sb);
+ sbflags = smb3_update_mnt_flags(cifs_sb);
if (ctx->direct_io)
cifs_dbg(FYI, "mounting share using direct i/o\n");
if (ctx->cache_ro) {
cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
+ sbflags |= CIFS_MOUNT_RO_CACHE;
} else if (ctx->cache_rw) {
cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
- cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
- CIFS_MOUNT_RW_CACHE);
+ sbflags |= CIFS_MOUNT_RO_CACHE | CIFS_MOUNT_RW_CACHE;
}
if ((ctx->cifs_acl) && (ctx->dynperm))
@@ -3617,16 +3515,19 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
if (ctx->prepath) {
cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL);
if (cifs_sb->prepath == NULL)
- return -ENOMEM;
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ rc = -ENOMEM;
+ else
+ sbflags |= CIFS_MOUNT_USE_PREFIX_PATH;
}
- return 0;
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
+ return rc;
}
/* Release all succeed connections */
void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx)
{
+ struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
int rc = 0;
if (mnt_ctx->tcon)
@@ -3638,7 +3539,7 @@ void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx)
mnt_ctx->ses = NULL;
mnt_ctx->tcon = NULL;
mnt_ctx->server = NULL;
- mnt_ctx->cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
+ atomic_andnot(CIFS_MOUNT_POSIX_PATHS, &cifs_sb->mnt_cifs_flags);
free_xid(mnt_ctx->xid);
}
@@ -3692,15 +3593,18 @@ out:
int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
{
struct TCP_Server_Info *server;
+ struct cifs_tcon *tcon = NULL;
struct cifs_sb_info *cifs_sb;
struct smb3_fs_context *ctx;
- struct cifs_tcon *tcon = NULL;
+ unsigned int sbflags;
int rc = 0;
- if (WARN_ON_ONCE(!mnt_ctx || !mnt_ctx->server || !mnt_ctx->ses || !mnt_ctx->fs_ctx ||
- !mnt_ctx->cifs_sb)) {
- rc = -EINVAL;
- goto out;
+ if (WARN_ON_ONCE(!mnt_ctx))
+ return -EINVAL;
+ if (WARN_ON_ONCE(!mnt_ctx->server || !mnt_ctx->ses ||
+ !mnt_ctx->fs_ctx || !mnt_ctx->cifs_sb)) {
+ mnt_ctx->tcon = NULL;
+ return -EINVAL;
}
server = mnt_ctx->server;
ctx = mnt_ctx->fs_ctx;
@@ -3714,9 +3618,16 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
goto out;
}
- /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
- if (tcon->posix_extensions)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+ /*
+ * if new SMB3.11 POSIX extensions are supported, do not change anything in the
+ * path (i.e., do not remap / and \ and do not map any special characters)
+ */
+ if (tcon->posix_extensions) {
+ atomic_or(CIFS_MOUNT_POSIX_PATHS, &cifs_sb->mnt_cifs_flags);
+ atomic_andnot(CIFS_MOUNT_MAP_SFM_CHR |
+ CIFS_MOUNT_MAP_SPECIAL_CHR,
+ &cifs_sb->mnt_cifs_flags);
+ }
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/* tell server which Unix caps we support */
@@ -3739,48 +3650,27 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
tcon->unix_ext = 0; /* server does not support them */
+ sbflags = cifs_sb_flags(cifs_sb);
/* do not care if a following call succeed - informational */
if (!tcon->pipe && server->ops->qfs_tcon) {
server->ops->qfs_tcon(mnt_ctx->xid, tcon, cifs_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
+ if (sbflags & CIFS_MOUNT_RO_CACHE) {
if (tcon->fsDevInfo.DeviceCharacteristics &
cpu_to_le32(FILE_READ_ONLY_DEVICE))
cifs_dbg(VFS, "mounted to read only share\n");
- else if ((cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_RW_CACHE) == 0)
+ else if (!(sbflags & CIFS_MOUNT_RW_CACHE))
cifs_dbg(VFS, "read only mount of RW share\n");
/* no need to log a RW mount of a typical RW share */
}
}
- /*
- * Clamp the rsize/wsize mount arguments if they are too big for the server
- * and set the rsize/wsize to the negotiated values if not passed in by
- * the user on mount
- */
- if ((cifs_sb->ctx->wsize == 0) ||
- (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) {
- cifs_sb->ctx->wsize =
- round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
- /*
- * in the very unlikely event that the server sent a max write size under PAGE_SIZE,
- * (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096
- */
- if (cifs_sb->ctx->wsize == 0) {
- cifs_sb->ctx->wsize = PAGE_SIZE;
- cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n");
- }
- }
- if ((cifs_sb->ctx->rsize == 0) ||
- (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
- cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
-
+ cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
/*
* The cookie is initialized from volume info returned above.
* Inside cifs_fscache_get_super_cookie it checks
* that we do not get super cookie twice.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
+ if (sbflags & CIFS_MOUNT_FSCACHE)
cifs_fscache_get_super_cookie(tcon);
out:
@@ -3794,7 +3684,7 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
struct tcon_link *tlink;
/* hang the tcon off of the superblock */
- tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
+ tlink = kzalloc_obj(*tlink);
if (tlink == NULL)
return -ENOMEM;
@@ -3903,7 +3793,8 @@ int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx)
cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
if (rc != 0) {
cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH,
+ &cifs_sb->mnt_cifs_flags);
rc = 0;
}
}
@@ -3913,15 +3804,64 @@ out:
return rc;
}
+static struct mchan_mount *
+mchan_mount_alloc(struct cifs_ses *ses)
+{
+ struct mchan_mount *mchan_mount;
+
+ mchan_mount = kzalloc_obj(*mchan_mount);
+ if (!mchan_mount)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_WORK(&mchan_mount->work, mchan_mount_work_fn);
+
+ spin_lock(&cifs_tcp_ses_lock);
+ cifs_smb_ses_inc_refcount(ses);
+ spin_unlock(&cifs_tcp_ses_lock);
+ mchan_mount->ses = ses;
+
+ return mchan_mount;
+}
+
+static void
+mchan_mount_free(struct mchan_mount *mchan_mount)
+{
+ cifs_put_smb_ses(mchan_mount->ses);
+ kfree(mchan_mount);
+}
+
+static void
+mchan_mount_work_fn(struct work_struct *work)
+{
+ struct mchan_mount *mchan_mount = container_of(work, struct mchan_mount, work);
+
+ smb3_update_ses_channels(mchan_mount->ses,
+ mchan_mount->ses->server,
+ false /* from_reconnect */,
+ false /* disable_mchan */);
+
+ mchan_mount_free(mchan_mount);
+}
+
#ifdef CONFIG_CIFS_DFS_UPCALL
int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
{
struct cifs_mount_ctx mnt_ctx = { .cifs_sb = cifs_sb, .fs_ctx = ctx, };
+ struct mchan_mount *mchan_mount = NULL;
int rc;
rc = dfs_mount_share(&mnt_ctx);
if (rc)
goto error;
+
+ if (ctx->multichannel) {
+ mchan_mount = mchan_mount_alloc(mnt_ctx.ses);
+ if (IS_ERR(mchan_mount)) {
+ rc = PTR_ERR(mchan_mount);
+ goto error;
+ }
+ }
+
if (!ctx->dfs_conn)
goto out;
@@ -3934,21 +3874,25 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
*/
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
kfree(cifs_sb->prepath);
cifs_sb->prepath = ctx->prepath;
ctx->prepath = NULL;
out:
- cifs_try_adding_channels(mnt_ctx.ses);
rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
if (rc)
goto error;
+ if (ctx->multichannel)
+ queue_work(cifsiod_wq, &mchan_mount->work);
+
free_xid(mnt_ctx.xid);
return rc;
error:
+ if (ctx->multichannel && !IS_ERR_OR_NULL(mchan_mount))
+ mchan_mount_free(mchan_mount);
cifs_mount_put_conns(&mnt_ctx);
return rc;
}
@@ -3957,6 +3901,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
{
int rc = 0;
struct cifs_mount_ctx mnt_ctx = { .cifs_sb = cifs_sb, .fs_ctx = ctx, };
+ struct mchan_mount *mchan_mount = NULL;
rc = cifs_mount_get_session(&mnt_ctx);
if (rc)
@@ -3984,161 +3929,32 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
if (rc)
goto error;
+ if (ctx->multichannel) {
+ mchan_mount = mchan_mount_alloc(mnt_ctx.ses);
+ if (IS_ERR(mchan_mount)) {
+ rc = PTR_ERR(mchan_mount);
+ goto error;
+ }
+ }
+
rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
if (rc)
goto error;
+ if (ctx->multichannel)
+ queue_work(cifsiod_wq, &mchan_mount->work);
+
free_xid(mnt_ctx.xid);
return rc;
error:
+ if (ctx->multichannel && !IS_ERR_OR_NULL(mchan_mount))
+ mchan_mount_free(mchan_mount);
cifs_mount_put_conns(&mnt_ctx);
return rc;
}
#endif
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-/*
- * Issue a TREE_CONNECT request.
- */
-int
-CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
- const char *tree, struct cifs_tcon *tcon,
- const struct nls_table *nls_codepage)
-{
- struct smb_hdr *smb_buffer;
- struct smb_hdr *smb_buffer_response;
- TCONX_REQ *pSMB;
- TCONX_RSP *pSMBr;
- unsigned char *bcc_ptr;
- int rc = 0;
- int length;
- __u16 bytes_left, count;
-
- if (ses == NULL)
- return -EIO;
-
- smb_buffer = cifs_buf_get();
- if (smb_buffer == NULL)
- return -ENOMEM;
-
- smb_buffer_response = smb_buffer;
-
- header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
- NULL /*no tid */, 4 /*wct */);
-
- smb_buffer->Mid = get_next_mid(ses->server);
- smb_buffer->Uid = ses->Suid;
- pSMB = (TCONX_REQ *) smb_buffer;
- pSMBr = (TCONX_RSP *) smb_buffer_response;
-
- pSMB->AndXCommand = 0xFF;
- pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
- bcc_ptr = &pSMB->Password[0];
-
- pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
- *bcc_ptr = 0; /* password is null byte */
- bcc_ptr++; /* skip password */
- /* already aligned so no need to do it below */
-
- if (ses->server->sign)
- smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
- if (ses->capabilities & CAP_STATUS32)
- smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-
- if (ses->capabilities & CAP_DFS)
- smb_buffer->Flags2 |= SMBFLG2_DFS;
-
- if (ses->capabilities & CAP_UNICODE) {
- smb_buffer->Flags2 |= SMBFLG2_UNICODE;
- length =
- cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
- 6 /* max utf8 char length in bytes */ *
- (/* server len*/ + 256 /* share len */), nls_codepage);
- bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
- bcc_ptr += 2; /* skip trailing null */
- } else { /* ASCII */
- strcpy(bcc_ptr, tree);
- bcc_ptr += strlen(tree) + 1;
- }
- strcpy(bcc_ptr, "?????");
- bcc_ptr += strlen("?????");
- bcc_ptr += 1;
- count = bcc_ptr - &pSMB->Password[0];
- be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
- pSMB->ByteCount = cpu_to_le16(count);
-
- rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
- 0);
-
- /* above now done in SendReceive */
- if (rc == 0) {
- bool is_unicode;
-
- tcon->tid = smb_buffer_response->Tid;
- bcc_ptr = pByteArea(smb_buffer_response);
- bytes_left = get_bcc(smb_buffer_response);
- length = strnlen(bcc_ptr, bytes_left - 2);
- if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
- is_unicode = true;
- else
- is_unicode = false;
-
-
- /* skip service field (NB: this field is always ASCII) */
- if (length == 3) {
- if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
- (bcc_ptr[2] == 'C')) {
- cifs_dbg(FYI, "IPC connection\n");
- tcon->ipc = true;
- tcon->pipe = true;
- }
- } else if (length == 2) {
- if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
- /* the most common case */
- cifs_dbg(FYI, "disk share connection\n");
- }
- }
- bcc_ptr += length + 1;
- bytes_left -= (length + 1);
- strscpy(tcon->tree_name, tree, sizeof(tcon->tree_name));
-
- /* mostly informational -- no need to fail on error here */
- kfree(tcon->nativeFileSystem);
- tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
- bytes_left, is_unicode,
- nls_codepage);
-
- cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
-
- if ((smb_buffer_response->WordCount == 3) ||
- (smb_buffer_response->WordCount == 7))
- /* field is in same location */
- tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
- else
- tcon->Flags = 0;
- cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
-
- /*
- * reset_cifs_unix_caps calls QFSInfo which requires
- * need_reconnect to be false, but we would not need to call
- * reset_caps if this were not a reconnect case so must check
- * need_reconnect flag here. The caller will also clear
- * need_reconnect when tcon was successful but needed to be
- * cleared earlier in the case of unix extensions reconnect
- */
- if (tcon->need_reconnect && tcon->unix_ext) {
- cifs_dbg(FYI, "resetting caps for %s\n", tcon->tree_name);
- tcon->need_reconnect = false;
- reset_cifs_unix_caps(xid, tcon, NULL, NULL);
- }
- }
- cifs_buf_release(smb_buffer);
- return rc;
-}
-#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
-
static void delayed_free(struct rcu_head *p)
{
struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu);
@@ -4211,6 +4027,7 @@ retry:
}
server->tcpStatus = CifsInNegotiate;
+ server->neg_start = jiffies;
spin_unlock(&server->srv_lock);
rc = server->ops->negotiate(xid, ses, server);
@@ -4249,8 +4066,10 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
bool is_binding = false;
+ bool new_ses;
spin_lock(&ses->ses_lock);
+ new_ses = ses->ses_status == SES_NEW;
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
__func__, ses->chans_need_reconnect);
@@ -4279,7 +4098,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
ses->ses_status = SES_IN_SETUP;
/* force iface_list refresh */
+ spin_lock(&ses->iface_lock);
ses->iface_last_update = 0;
+ spin_unlock(&ses->iface_lock);
}
spin_unlock(&ses->ses_lock);
@@ -4336,7 +4157,10 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
}
if (rc) {
- cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
+ if (new_ses) {
+ cifs_server_dbg(VFS, "failed to create a new SMB session with %s: %d\n",
+ get_security_type_str(ses->sectype), rc);
+ }
spin_lock(&ses->ses_lock);
if (ses->ses_status == SES_IN_SETUP)
ses->ses_status = SES_NEED_RECON;
@@ -4380,7 +4204,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
struct smb3_fs_context *ctx;
char *origin_fullpath = NULL;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (ctx == NULL)
return ERR_PTR(-ENOMEM);
@@ -4463,6 +4287,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
out:
kfree(ctx->username);
+ kfree(ctx->domainname);
kfree_sensitive(ctx->password);
kfree(origin_fullpath);
kfree(ctx);
@@ -4543,7 +4368,7 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
kuid_t fsuid = current_fsuid();
int err;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
spin_lock(&cifs_sb->tlink_tree_lock);
@@ -4553,7 +4378,7 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
spin_unlock(&cifs_sb->tlink_tree_lock);
if (tlink == NULL) {
- newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
+ newtlink = kzalloc_obj(*tlink);
if (newtlink == NULL)
return ERR_PTR(-ENOMEM);
newtlink->tl_uid = fsuid;
diff --git a/fs/smb/client/dfs.h b/fs/smb/client/dfs.h
index e60f0a24a8a1..16ac2cdd5c82 100644
--- a/fs/smb/client/dfs.h
+++ b/fs/smb/client/dfs.h
@@ -46,7 +46,7 @@ static inline struct dfs_ref_walk *ref_walk_alloc(void)
{
struct dfs_ref_walk *rw;
- rw = kmalloc(sizeof(*rw), GFP_KERNEL);
+ rw = kmalloc_obj(*rw);
if (!rw)
return ERR_PTR(-ENOMEM);
return rw;
@@ -151,7 +151,8 @@ static inline void ref_walk_mark_end(struct dfs_ref_walk *rw)
ref->tit = ERR_PTR(-ENOENT); /* end marker */
}
-int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref,
+int dfs_parse_target_referral(const char *full_path,
+ const struct dfs_info3_param *ref,
struct smb3_fs_context *ctx);
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx);
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 4dada26d56b5..83f8cf2f8d2b 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -363,7 +363,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
{
struct cache_dfs_tgt *t;
- t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ t = kmalloc_obj(*t, GFP_ATOMIC);
if (!t)
return ERR_PTR(-ENOMEM);
t->name = kstrdup(name, GFP_ATOMIC);
@@ -796,7 +796,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl)
INIT_LIST_HEAD(head);
list_for_each_entry(t, &ce->tlist, list) {
- it = kzalloc(sizeof(*it), GFP_ATOMIC);
+ it = kzalloc_obj(*it, GFP_ATOMIC);
if (!it) {
rc = -ENOMEM;
goto err_free_it;
@@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
return match;
}
-static bool is_ses_good(struct cifs_ses *ses)
+static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
{
struct TCP_Server_Info *server = ses->server;
- struct cifs_tcon *tcon = ses->tcon_ipc;
+ struct cifs_tcon *ipc = NULL;
bool ret;
+ spin_lock(&cifs_tcp_ses_lock);
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
+
ret = !cifs_chan_needs_reconnect(ses, server) &&
- ses->ses_status == SES_GOOD &&
- !tcon->need_reconnect;
+ ses->ses_status == SES_GOOD;
+
spin_unlock(&ses->chan_lock);
+
+ if (!ret)
+ goto out;
+
+ if (likely(ses->tcon_ipc)) {
+ if (ses->tcon_ipc->need_reconnect) {
+ ret = false;
+ goto out;
+ }
+ } else {
+ spin_unlock(&ses->ses_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+
+ ipc = cifs_setup_ipc(ses, tcon->seal);
+
+ spin_lock(&cifs_tcp_ses_lock);
+ spin_lock(&ses->ses_lock);
+ if (!IS_ERR(ipc)) {
+ if (!ses->tcon_ipc) {
+ ses->tcon_ipc = ipc;
+ ipc = NULL;
+ }
+ } else {
+ ret = false;
+ ipc = NULL;
+ }
+ }
+
+out:
spin_unlock(&ses->ses_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ if (ipc && server->ops->tree_disconnect) {
+ unsigned int xid = get_xid();
+
+ (void)server->ops->tree_disconnect(xid, ipc);
+ _free_xid(xid);
+ }
+ tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
return ret;
}
/* Refresh dfs referral of @ses */
-static void refresh_ses_referral(struct cifs_ses *ses)
+static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
{
struct cache_entry *ce;
unsigned int xid;
@@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
}
ses = CIFS_DFS_ROOT_SES(ses);
- if (!is_ses_good(ses)) {
+ if (!is_ses_good(tcon, ses)) {
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
__func__);
goto out;
@@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
up_read(&htable_rw_lock);
ses = CIFS_DFS_ROOT_SES(ses);
- if (!is_ses_good(ses)) {
+ if (!is_ses_good(tcon, ses)) {
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
__func__);
goto out;
@@ -1294,7 +1333,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
*/
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
refresh_tcon_referral(tcon, true);
return 0;
@@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
- refresh_ses_referral(ses);
+ refresh_ses_referral(tcon, ses);
refresh_tcon_referral(tcon, false);
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
diff --git a/fs/smb/client/dfs_cache.h b/fs/smb/client/dfs_cache.h
index 18a08a2ca93b..c99dc3546c70 100644
--- a/fs/smb/client/dfs_cache.h
+++ b/fs/smb/client/dfs_cache.h
@@ -37,17 +37,22 @@ int dfs_cache_init(void);
void dfs_cache_destroy(void);
extern const struct proc_ops dfscache_proc_ops;
-int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *cp,
- int remap, const char *path, struct dfs_info3_param *ref,
+int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ const struct nls_table *cp, int remap, const char *path,
+ struct dfs_info3_param *ref,
struct dfs_cache_tgt_list *tgt_list);
int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
struct dfs_cache_tgt_list *tgt_list);
-void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it);
-int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it,
+void dfs_cache_noreq_update_tgthint(const char *path,
+ const struct dfs_cache_tgt_iterator *it);
+int dfs_cache_get_tgt_referral(const char *path,
+ const struct dfs_cache_tgt_iterator *it,
struct dfs_info3_param *ref);
-int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
- char **prefix);
-char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp, int remap);
+int dfs_cache_get_tgt_share(char *path,
+ const struct dfs_cache_tgt_iterator *it,
+ char **share, char **prefix);
+char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp,
+ int remap);
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb);
void dfs_cache_refresh(struct work_struct *work);
diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index d1e95632ac54..e4295a5b55b3 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -14,7 +14,6 @@
#include <linux/mount.h>
#include <linux/file.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -23,6 +22,7 @@
#include "fs_context.h"
#include "cifs_ioctl.h"
#include "fscache.h"
+#include "cached_dir.h"
static void
renew_parental_timestamps(struct dentry *direntry)
@@ -82,10 +82,11 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
const char *tree, int tree_len,
bool prefix)
{
- int dfsplen;
- int pplen = 0;
- struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
char dirsep = CIFS_DIR_SEP(cifs_sb);
+ int pplen = 0;
+ int dfsplen;
char *s;
if (unlikely(!page))
@@ -96,7 +97,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
else
dfsplen = 0;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if (sbflags & CIFS_MOUNT_USE_PREFIX_PATH)
pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
s = dentry_path_raw(direntry, page, PATH_MAX);
@@ -123,7 +124,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
if (dfsplen) {
s -= dfsplen;
memcpy(s, tree, dfsplen);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
+ if (sbflags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < dfsplen; i++) {
if (s[i] == '\\')
@@ -152,7 +153,7 @@ char *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page
static int
check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
int i;
if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
@@ -160,7 +161,7 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
return -ENAMETOOLONG;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') {
cifs_dbg(FYI, "Invalid file name\n");
@@ -171,45 +172,67 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
return 0;
}
+static char *alloc_parent_path(struct dentry *dentry, size_t namelen)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry);
+ void *page = alloc_dentry_path();
+ const char *path;
+ size_t size;
+ char *npath;
-/* Inode operations in similar order to how they appear in Linux file fs.h */
+ path = build_path_from_dentry(dentry->d_parent, page);
+ if (IS_ERR(path)) {
+ npath = ERR_CAST(path);
+ goto out;
+ }
+
+ size = strlen(path) + namelen + 2;
+ npath = kmalloc(size, GFP_KERNEL);
+ if (!npath)
+ npath = ERR_PTR(-ENOMEM);
+ else
+ scnprintf(npath, size, "%s%c", path, CIFS_DIR_SEP(cifs_sb));
+out:
+ free_dentry_path(page);
+ return npath;
+}
-static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
- struct tcon_link *tlink, unsigned int oflags, umode_t mode, __u32 *oplock,
- struct cifs_fid *fid, struct cifs_open_info_data *buf)
+/* Inode operations in similar order to how they appear in Linux file fs.h */
+static int __cifs_do_create(struct inode *dir, struct dentry *direntry,
+ const char *full_path, unsigned int xid,
+ struct tcon_link *tlink, unsigned int oflags,
+ umode_t mode, __u32 *oplock, struct cifs_fid *fid,
+ struct cifs_open_info_data *buf,
+ struct inode **inode)
{
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
int desired_access;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
struct cifs_tcon *tcon = tlink_tcon(tlink);
- const char *full_path;
- void *page = alloc_dentry_path();
struct inode *newinode = NULL;
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
int disposition;
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
+ struct cached_fid *parent_cfid = NULL;
int rdwr_for_fscache = 0;
+ __le32 lease_flags = 0;
+ *inode = NULL;
*oplock = 0;
if (tcon->ses->server->oplocks)
*oplock = REQ_OPLOCK;
- full_path = build_path_from_dentry(direntry, page);
- if (IS_ERR(full_path)) {
- free_dentry_path(page);
- return PTR_ERR(full_path);
- }
-
/* If we're caching, we need to be able to fill in around partial writes. */
- if (cifs_fscache_enabled(inode) && (oflags & O_ACCMODE) == O_WRONLY)
+ if (cifs_fscache_enabled(dir) && (oflags & O_ACCMODE) == O_WRONLY)
rdwr_for_fscache = 1;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
- rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+ rc = cifs_posix_open(full_path, &newinode, dir->i_sb, mode,
oflags, oplock, &fid->netfid, xid);
switch (rc) {
case 0:
@@ -221,8 +244,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
if (S_ISDIR(newinode->i_mode)) {
CIFSSMBClose(xid, tcon, fid->netfid);
iput(newinode);
- rc = -EISDIR;
- goto out;
+ return -EISDIR;
}
if (!S_ISREG(newinode->i_mode)) {
@@ -265,7 +287,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
break;
default:
- goto out;
+ return rc;
}
/*
* fallthrough to retry, using older open call, this is case
@@ -283,27 +305,32 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
desired_access |= GENERIC_WRITE;
if (rdwr_for_fscache == 1)
desired_access |= GENERIC_READ;
+ if (oflags & O_TMPFILE)
+ desired_access |= DELETE;
disposition = FILE_OVERWRITE_IF;
- if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ if (oflags & O_CREAT) {
+ if (oflags & O_EXCL)
+ disposition = FILE_CREATE;
+ else if (oflags & O_TRUNC)
+ disposition = FILE_OVERWRITE_IF;
+ else
+ disposition = FILE_OPEN_IF;
+ } else if (oflags & O_TMPFILE) {
disposition = FILE_CREATE;
- else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
- disposition = FILE_OVERWRITE_IF;
- else if ((oflags & O_CREAT) == O_CREAT)
- disposition = FILE_OPEN_IF;
- else
+ } else {
cifs_dbg(FYI, "Create flag not set in create function\n");
+ }
/*
* BB add processing to set equivalent of mode - e.g. via CreateX with
* ACLs
*/
- if (!server->ops->open) {
- rc = -ENOSYS;
- goto out;
- }
+ if (!server->ops->open)
+ return -EOPNOTSUPP;
+ create_options |= cifs_open_create_options(oflags, create_options);
/*
* if we're not using unix extensions, see if we need to set
* ATTR_READONLY on the create call
@@ -311,7 +338,29 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
create_options |= CREATE_OPTION_READONLY;
+
retry_open:
+ if (tcon->cfids && direntry->d_parent && server->dialect >= SMB30_PROT_ID) {
+ parent_cfid = NULL;
+ spin_lock(&tcon->cfids->cfid_list_lock);
+ list_for_each_entry(parent_cfid, &tcon->cfids->entries, entry) {
+ if (parent_cfid->dentry == direntry->d_parent) {
+ cifs_dbg(FYI, "found a parent cached file handle\n");
+ if (is_valid_cached_dir(parent_cfid)) {
+ lease_flags
+ |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
+ memcpy(fid->parent_lease_key,
+ parent_cfid->fid.lease_key,
+ SMB2_LEASE_KEY_SIZE);
+ parent_cfid->dirents.is_valid = false;
+ parent_cfid->dirents.is_failed = true;
+ }
+ break;
+ }
+ }
+ spin_unlock(&tcon->cfids->cfid_list_lock);
+ }
+
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.cifs_sb = cifs_sb,
@@ -320,6 +369,7 @@ retry_open:
.disposition = disposition,
.path = full_path,
.fid = fid,
+ .lease_flags = lease_flags,
.mode = mode,
};
rc = server->ops->open(xid, &oparms, oplock, buf);
@@ -330,10 +380,10 @@ retry_open:
rdwr_for_fscache = 2;
goto retry_open;
}
- goto out;
+ return rc;
}
if (rdwr_for_fscache == 2)
- cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE);
+ cifs_invalidate_cache(dir, FSCACHE_INVAL_DIO_WRITE);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/*
@@ -349,10 +399,10 @@ retry_open:
.device = 0,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
- if (inode->i_mode & S_ISGID)
- args.gid = inode->i_gid;
+ if (dir->i_mode & S_ISGID)
+ args.gid = dir->i_gid;
else
args.gid = current_fsgid();
} else {
@@ -374,24 +424,24 @@ retry_open:
cifs_create_get_file_info:
/* server might mask mode so we have to query for it */
if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+ rc = cifs_get_inode_info_unix(&newinode, full_path, dir->i_sb,
xid);
else {
#else
{
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* TODO: Add support for calling POSIX query info here, but passing in fid */
- rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, xid, fid);
+ rc = cifs_get_inode_info(&newinode, full_path, buf, dir->i_sb, xid, fid);
if (newinode) {
if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid);
if ((*oplock & CIFS_CREATE_ACTION) && S_ISREG(newinode->i_mode)) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
newinode->i_uid = current_fsuid();
- if (inode->i_mode & S_ISGID)
- newinode->i_gid = inode->i_gid;
+ if (dir->i_mode & S_ISGID)
+ newinode->i_gid = dir->i_gid;
else
newinode->i_gid = current_fsgid();
}
@@ -408,17 +458,12 @@ cifs_create_set_dentry:
goto out_err;
}
- if (newinode)
- if (S_ISDIR(newinode->i_mode)) {
- rc = -EISDIR;
- goto out_err;
- }
-
- d_drop(direntry);
- d_add(direntry, newinode);
+ if (newinode && S_ISDIR(newinode->i_mode)) {
+ rc = -EISDIR;
+ goto out_err;
+ }
-out:
- free_dentry_path(page);
+ *inode = newinode;
return rc;
out_err:
@@ -426,26 +471,60 @@ out_err:
server->ops->close(xid, tcon, fid);
if (newinode)
iput(newinode);
- goto out;
+ return rc;
}
-int
-cifs_atomic_open(struct inode *inode, struct dentry *direntry,
- struct file *file, unsigned oflags, umode_t mode)
+static int cifs_do_create(struct inode *dir, struct dentry *direntry,
+ unsigned int xid, struct tcon_link *tlink,
+ unsigned int oflags, umode_t mode,
+ __u32 *oplock, struct cifs_fid *fid,
+ struct cifs_open_info_data *buf,
+ struct inode **inode)
{
+ void *page = alloc_dentry_path();
+ const char *full_path;
int rc;
- unsigned int xid;
- struct tcon_link *tlink;
- struct cifs_tcon *tcon;
+
+ full_path = build_path_from_dentry(direntry, page);
+ if (IS_ERR(full_path)) {
+ rc = PTR_ERR(full_path);
+ } else {
+ rc = __cifs_do_create(dir, direntry, full_path, xid,
+ tlink, oflags, mode, oplock,
+ fid, buf, inode);
+ }
+ free_dentry_path(page);
+ return rc;
+}
+
+
+/*
+ * Look up, create and open a CIFS file.
+ *
+ * The initial dentry state is in-lookup or hashed-negative. On success, dentry
+ * will become hashed-positive by calling d_splice_alias() if in-lookup,
+ * otherwise d_instantiate().
+ */
+int cifs_atomic_open(struct inode *dir, struct dentry *direntry,
+ struct file *file, unsigned int oflags, umode_t mode)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
+ struct cifs_open_info_data buf = {};
struct TCP_Server_Info *server;
- struct cifs_fid fid = {};
+ struct cifsFileInfo *file_info;
struct cifs_pending_open open;
+ struct cifs_fid fid = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ struct dentry *alias;
+ struct inode *inode;
+ unsigned int xid;
__u32 oplock;
- struct cifsFileInfo *file_info;
- struct cifs_open_info_data buf = {};
+ int rc;
- if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
- return -EIO;
+ if (unlikely(cifs_forced_shutdown(cifs_sb)))
+ return smb_EIO(smb_eio_trace_forced_shutdown);
/*
* Posix open is only called (at lookup time) for file create now. For
@@ -459,8 +538,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
* in network traffic in the other paths.
*/
if (!(oflags & O_CREAT)) {
- struct dentry *res;
-
/*
* Check for hashed negative dentry. We have already revalidated
* the dentry and it is fine. No need to perform another lookup.
@@ -468,19 +545,15 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
if (!d_in_lookup(direntry))
return -ENOENT;
- res = cifs_lookup(inode, direntry, 0);
- if (IS_ERR(res))
- return PTR_ERR(res);
-
- return finish_no_open(file, res);
+ return finish_no_open(file, cifs_lookup(dir, direntry, 0));
}
xid = get_xid();
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
- inode, direntry, direntry);
+ dir, direntry, direntry);
- tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+ tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
goto out_free_xid;
@@ -499,13 +572,21 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
cifs_add_pending_open(&fid, tlink, &open);
- rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fid, &buf);
+ rc = cifs_do_create(dir, direntry, xid, tlink, oflags, mode,
+ &oplock, &fid, &buf, &inode);
if (rc) {
cifs_del_pending_open(&open);
goto out;
}
+ if (d_in_lookup(direntry)) {
+ alias = d_splice_alias(inode, direntry);
+ if (!IS_ERR_OR_NULL(alias))
+ direntry = alias;
+ } else {
+ d_instantiate(direntry, inode);
+ }
+
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
file->f_mode |= FMODE_CREATED;
@@ -517,13 +598,13 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
goto out;
}
- if (file->f_flags & O_DIRECT &&
- CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
file->f_op = &cifs_file_direct_nobrl_ops;
else
file->f_op = &cifs_file_direct_ops;
- }
+ }
file_info = cifs_new_fileinfo(&fid, file, tlink, oplock, buf.symlink_target);
if (file_info == NULL) {
@@ -545,9 +626,16 @@ out_free_xid:
return rc;
}
-int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
+/*
+ * Create a CIFS file.
+ *
+ * The initial dentry state is hashed-negative. On success, dentry will become
+ * hashed-positive by calling d_instantiate().
+ */
+int cifs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *direntry, umode_t mode, bool excl)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
int rc;
unsigned int xid = get_xid();
/*
@@ -561,19 +649,20 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
struct tcon_link *tlink;
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
+ struct inode *inode;
struct cifs_fid fid;
__u32 oplock;
struct cifs_open_info_data buf = {};
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
- inode, direntry, direntry);
+ dir, direntry, direntry);
- if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) {
- rc = -EIO;
+ if (unlikely(cifs_forced_shutdown(cifs_sb))) {
+ rc = smb_EIO(smb_eio_trace_forced_shutdown);
goto out_free_xid;
}
- tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+ tlink = cifs_sb_tlink(cifs_sb);
rc = PTR_ERR(tlink);
if (IS_ERR(tlink))
goto out_free_xid;
@@ -584,9 +673,13 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
if (server->ops->new_lease_key)
server->ops->new_lease_key(&fid);
- rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf);
- if (!rc && server->ops->close)
- server->ops->close(xid, tcon, &fid);
+ rc = cifs_do_create(dir, direntry, xid, tlink, oflags,
+ mode, &oplock, &fid, &buf, &inode);
+ if (!rc) {
+ d_instantiate(direntry, inode);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &fid);
+ }
cifs_free_open_info(&buf);
cifs_put_tlink(tlink);
@@ -611,7 +704,7 @@ int cifs_mknod(struct mnt_idmap *idmap, struct inode *inode,
cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -658,6 +751,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
const char *full_path;
void *page;
int retry_count = 0;
+ struct dentry *de;
xid = get_xid();
@@ -669,16 +763,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
- free_xid(xid);
- return ERR_CAST(tlink);
+ de = ERR_CAST(tlink);
+ goto free_xid;
}
pTcon = tlink_tcon(tlink);
rc = check_name(direntry, pTcon);
if (unlikely(rc)) {
- cifs_put_tlink(tlink);
- free_xid(xid);
- return ERR_PTR(rc);
+ de = ERR_PTR(rc);
+ goto put_tlink;
}
/* can not grab the rename sem here since it would
@@ -687,16 +780,38 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
page = alloc_dentry_path();
full_path = build_path_from_dentry(direntry, page);
if (IS_ERR(full_path)) {
- cifs_put_tlink(tlink);
- free_xid(xid);
- free_dentry_path(page);
- return ERR_CAST(full_path);
+ de = ERR_CAST(full_path);
+ goto free_dentry_path;
}
if (d_really_is_positive(direntry)) {
cifs_dbg(FYI, "non-NULL inode in lookup\n");
} else {
+ struct cached_fid *cfid = NULL;
+
cifs_dbg(FYI, "NULL inode in lookup\n");
+
+ /*
+ * We can only rely on negative dentries having the same
+ * spelling as the cached dirent if case insensitivity is
+ * forced on mount.
+ *
+ * XXX: if servers correctly announce Case Sensitivity Search
+ * on GetInfo of FileFSAttributeInformation, then we can take
+ * correct action even if case insensitive is not forced on
+ * mount.
+ */
+ if (pTcon->nocase && !open_cached_dir_by_dentry(pTcon, direntry->d_parent, &cfid)) {
+ /*
+ * dentry is negative and parent is fully cached:
+ * we can assume file does not exist
+ */
+ if (cfid->dirents.is_valid) {
+ close_cached_dir(cfid);
+ goto out;
+ }
+ close_cached_dir(cfid);
+ }
}
cifs_dbg(FYI, "Full path: %s inode = 0x%p\n",
full_path, d_inode(direntry));
@@ -730,24 +845,29 @@ again:
}
newInode = ERR_PTR(rc);
}
+
+out:
+ de = d_splice_alias(newInode, direntry);
+free_dentry_path:
free_dentry_path(page);
+put_tlink:
cifs_put_tlink(tlink);
+free_xid:
free_xid(xid);
- return d_splice_alias(newInode, direntry);
+ return de;
}
static int
cifs_d_revalidate(struct inode *dir, const struct qstr *name,
struct dentry *direntry, unsigned int flags)
{
- struct inode *inode;
- int rc;
-
if (flags & LOOKUP_RCU)
return -ECHILD;
if (d_really_is_positive(direntry)) {
- inode = d_inode(direntry);
+ int rc;
+ struct inode *inode = d_inode(direntry);
+
if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
CIFS_I(inode)->time = 0; /* force reval */
@@ -787,6 +907,22 @@ cifs_d_revalidate(struct inode *dir, const struct qstr *name,
return 1;
}
+ } else {
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir->i_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct cached_fid *cfid;
+
+ if (!open_cached_dir_by_dentry(tcon, direntry->d_parent, &cfid)) {
+ /*
+ * dentry is negative and parent is fully cached:
+ * we can assume file does not exist
+ */
+ if (cfid->dirents.is_valid) {
+ close_cached_dir(cfid);
+ return 1;
+ }
+ close_cached_dir(cfid);
+ }
}
/*
@@ -892,6 +1028,170 @@ static int cifs_ci_compare(const struct dentry *dentry,
return 0;
}
+static int set_tmpfile_attr(const unsigned int xid, unsigned int oflags,
+ struct inode *inode, const char *full_path,
+ struct TCP_Server_Info *server)
+{
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ FILE_BASIC_INFO fi;
+
+ cinode->cifsAttrs |= ATTR_HIDDEN;
+ if (oflags & O_EXCL)
+ cinode->cifsAttrs |= ATTR_TEMPORARY;
+
+ fi = (FILE_BASIC_INFO) {
+ .Attributes = cpu_to_le32(cinode->cifsAttrs),
+ };
+ return server->ops->set_file_info(inode, full_path, &fi, xid);
+}
+
+/*
+ * Create a hidden temporary CIFS file with delete-on-close bit set.
+ *
+ * The initial dentry state is unhashed-negative. On success, dentry will
+ * become unhashed-positive by calling d_instantiate().
+ */
+int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
+ struct file *file, umode_t mode)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
+ size_t namesize = CIFS_TMPNAME_LEN + 1;
+ char *path __free(kfree) = NULL, *name;
+ unsigned int oflags = file->f_flags;
+ int retries = 0, max_retries = 16;
+ struct TCP_Server_Info *server;
+ struct cifs_pending_open open;
+ struct cifsFileInfo *cfile;
+ struct cifs_fid fid = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ struct inode *inode;
+ unsigned int xid;
+ __u32 oplock;
+ int namelen;
+ int rc;
+
+ if (unlikely(cifs_forced_shutdown(cifs_sb)))
+ return smb_EIO(smb_eio_trace_forced_shutdown);
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ xid = get_xid();
+
+ if (server->vals->protocol_id < SMB20_PROT_ID) {
+ cifs_dbg(VFS | ONCE, "O_TMPFILE is supported only in SMB2+\n");
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (server->ops->new_lease_key)
+ server->ops->new_lease_key(&fid);
+ cifs_add_pending_open(&fid, tlink, &open);
+
+ path = alloc_parent_path(dentry, namesize - 1);
+ if (IS_ERR(path)) {
+ cifs_del_pending_open(&open);
+ rc = PTR_ERR(path);
+ path = NULL;
+ goto out;
+ }
+
+ name = path + strlen(path);
+ do {
+ /* Append tmpfile name to @path */
+ namelen = scnprintf(name, namesize, CIFS_TMPNAME_PREFIX "%x",
+ atomic_inc_return(&cifs_tmpcounter));
+ rc = __cifs_do_create(dir, dentry, path, xid, tlink, oflags,
+ mode, &oplock, &fid, NULL, &inode);
+ if (!rc) {
+ rc = d_mark_tmpfile_name(file, &QSTR_LEN(name, namelen));
+ if (rc) {
+ cifs_dbg(VFS | ONCE, "%s: failed to set filename in dentry: %d\n",
+ __func__, rc);
+ rc = -EISDIR;
+ iput(inode);
+ goto err_open;
+ }
+ set_nlink(inode, 0);
+ mark_inode_dirty(inode);
+ d_instantiate(dentry, inode);
+ break;
+ }
+ } while (unlikely(rc == -EEXIST) && ++retries < max_retries);
+
+ if (rc) {
+ cifs_del_pending_open(&open);
+ goto out;
+ }
+
+ rc = finish_open(file, dentry, generic_file_open);
+ if (rc)
+ goto err_open;
+
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
+ file->f_op = &cifs_file_direct_nobrl_ops;
+ else
+ file->f_op = &cifs_file_direct_ops;
+ }
+
+ cfile = cifs_new_fileinfo(&fid, file, tlink, oplock, NULL);
+ if (!cfile) {
+ rc = -ENOMEM;
+ goto err_open;
+ }
+
+ rc = set_tmpfile_attr(xid, oflags, inode, path, server);
+ if (rc)
+ goto out;
+
+ fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
+ file->f_mode & FMODE_WRITE);
+out:
+ cifs_put_tlink(tlink);
+ free_xid(xid);
+ return rc;
+err_open:
+ cifs_del_pending_open(&open);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &fid);
+ goto out;
+}
+
+char *cifs_silly_fullpath(struct dentry *dentry)
+{
+ unsigned char name[CIFS_SILLYNAME_LEN + 1];
+ int retries = 0, max_retries = 16;
+ size_t namesize = sizeof(name);
+ struct dentry *sdentry = NULL;
+ char *path;
+
+ do {
+ dput(sdentry);
+ scnprintf(name, namesize, CIFS_SILLYNAME_PREFIX "%x",
+ atomic_inc_return(&cifs_sillycounter));
+ sdentry = lookup_noperm(&QSTR(name), dentry->d_parent);
+ if (IS_ERR(sdentry))
+ return ERR_CAST(sdentry);
+ if (d_is_negative(sdentry)) {
+ dput(sdentry);
+ path = alloc_parent_path(dentry, CIFS_SILLYNAME_LEN);
+ if (!IS_ERR(path))
+ strcat(path, name);
+ return path;
+ }
+ } while (++retries < max_retries);
+ dput(sdentry);
+ return ERR_PTR(-EBUSY);
+}
+
const struct dentry_operations cifs_ci_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
.d_hash = cifs_ci_hash,
diff --git a/fs/smb/client/dns_resolve.h b/fs/smb/client/dns_resolve.h
index 0dc706f2c422..951fbab5e61d 100644
--- a/fs/smb/client/dns_resolve.h
+++ b/fs/smb/client/dns_resolve.h
@@ -15,10 +15,8 @@
#include "cifsglob.h"
#include "cifsproto.h"
-#ifdef __KERNEL__
-
-int dns_resolve_name(const char *dom, const char *name,
- size_t namelen, struct sockaddr *ip_addr);
+int dns_resolve_name(const char *dom, const char *name, size_t namelen,
+ struct sockaddr *ip_addr);
static inline int dns_resolve_unc(const char *dom, const char *unc,
struct sockaddr *ip_addr)
@@ -36,6 +34,4 @@ static inline int dns_resolve_unc(const char *dom, const char *unc,
return dns_resolve_name(dom, name, namelen, ip_addr);
}
-#endif /* KERNEL */
-
#endif /* _DNS_RESOLVE_H */
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 9e8f404b9e56..664a2c223089 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -9,12 +9,12 @@
*
*/
#include <linux/fs.h>
+#include <linux/fs_struct.h>
#include <linux/filelock.h>
#include <linux/backing-dev.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/pagemap.h>
-#include <linux/pagevec.h>
#include <linux/writeback.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/delay.h>
@@ -24,7 +24,6 @@
#include <linux/mm.h>
#include <asm/div64.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "smb2proto.h"
@@ -52,6 +51,7 @@ static void cifs_prepare_write(struct netfs_io_subrequest *subreq)
struct netfs_io_stream *stream = &req->rreq.io_streams[subreq->stream_nr];
struct TCP_Server_Info *server;
struct cifsFileInfo *open_file = req->cfile;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(wdata->rreq->inode->i_sb);
size_t wsize = req->rreq.wsize;
int rc;
@@ -63,6 +63,10 @@ static void cifs_prepare_write(struct netfs_io_subrequest *subreq)
server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses);
wdata->server = server;
+ if (cifs_sb->ctx->wsize == 0)
+ cifs_negotiate_wsize(server, cifs_sb->ctx,
+ tlink_tcon(req->cfile->tlink));
+
retry:
if (open_file->invalidHandle) {
rc = cifs_reopen_file(open_file, false);
@@ -92,8 +96,12 @@ retry:
cifs_trace_rw_credits_write_prepare);
#ifdef CONFIG_CIFS_SMB_DIRECT
- if (server->smbd_conn)
- stream->sreq_max_segs = server->smbd_conn->max_frmr_depth;
+ if (server->smbd_conn) {
+ const struct smbdirect_socket_parameters *sp =
+ smbd_get_parameters(server->smbd_conn);
+
+ stream->sreq_max_segs = sp->max_frmr_depth;
+ }
#endif
}
@@ -108,7 +116,7 @@ static void cifs_issue_write(struct netfs_io_subrequest *subreq)
int rc;
if (cifs_forced_shutdown(sbi)) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_forced_shutdown);
goto fail;
}
@@ -130,7 +138,7 @@ fail:
else
trace_netfs_sreq(subreq, netfs_sreq_trace_fail);
add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
- cifs_write_subrequest_terminated(wdata, rc, false);
+ cifs_write_subrequest_terminated(wdata, rc);
goto out;
}
@@ -161,9 +169,8 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq)
rdata->server = server;
if (cifs_sb->ctx->rsize == 0)
- cifs_sb->ctx->rsize =
- server->ops->negotiate_rsize(tlink_tcon(req->cfile->tlink),
- cifs_sb->ctx);
+ cifs_negotiate_rsize(server, cifs_sb->ctx,
+ tlink_tcon(req->cfile->tlink));
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
&size, &rdata->credits);
@@ -183,8 +190,12 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq)
cifs_trace_rw_credits_read_submit);
#ifdef CONFIG_CIFS_SMB_DIRECT
- if (server->smbd_conn)
- rreq->io_streams[0].sreq_max_segs = server->smbd_conn->max_frmr_depth;
+ if (server->smbd_conn) {
+ const struct smbdirect_socket_parameters *sp =
+ smbd_get_parameters(server->smbd_conn);
+
+ rreq->io_streams[0].sreq_max_segs = sp->max_frmr_depth;
+ }
#endif
return 0;
}
@@ -219,7 +230,8 @@ static void cifs_issue_read(struct netfs_io_subrequest *subreq)
goto failed;
}
- if (subreq->rreq->origin != NETFS_DIO_READ)
+ if (subreq->rreq->origin != NETFS_UNBUFFERED_READ &&
+ subreq->rreq->origin != NETFS_DIO_READ)
__set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
@@ -242,7 +254,7 @@ static void cifs_begin_writeback(struct netfs_io_request *wreq)
struct cifs_io_request *req = container_of(wreq, struct cifs_io_request, rreq);
int ret;
- ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_WR_ANY, &req->cfile);
+ ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_ANY, &req->cfile);
if (ret) {
cifs_dbg(VFS, "No writable handle in writepages ret=%d\n", ret);
return;
@@ -257,7 +269,7 @@ static void cifs_begin_writeback(struct netfs_io_request *wreq)
static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
{
struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq);
- struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode);
struct cifsFileInfo *open_file = NULL;
rreq->rsize = cifs_sb->ctx->rsize;
@@ -268,11 +280,11 @@ static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
open_file = file->private_data;
rreq->netfs_priv = file->private_data;
req->cfile = cifsFileInfo_get(open_file);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RWPIDFORWARD)
req->pid = req->cfile->pid;
} else if (rreq->origin != NETFS_WRITEBACK) {
WARN_ON_ONCE(1);
- return -EIO;
+ return smb_EIO1(smb_eio_trace_not_netfs_writeback, rreq->origin);
}
return 0;
@@ -381,7 +393,7 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
}
spin_unlock(&tcon->open_file_lock);
- invalidate_all_cached_dirs(tcon);
+ invalidate_all_cached_dirs(tcon, true);
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_IN_FILES_INVALIDATE)
tcon->status = TID_NEED_TCON;
@@ -393,22 +405,29 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
*/
}
-static inline int cifs_convert_flags(unsigned int flags, int rdwr_for_fscache)
+static inline int cifs_convert_flags(unsigned int oflags, int rdwr_for_fscache)
{
- if ((flags & O_ACCMODE) == O_RDONLY)
- return GENERIC_READ;
- else if ((flags & O_ACCMODE) == O_WRONLY)
- return rdwr_for_fscache == 1 ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE;
- else if ((flags & O_ACCMODE) == O_RDWR) {
+ int flags = 0;
+
+ if (oflags & O_TMPFILE)
+ flags |= DELETE;
+
+ if ((oflags & O_ACCMODE) == O_RDONLY)
+ return flags | GENERIC_READ;
+ if ((oflags & O_ACCMODE) == O_WRONLY) {
+ return flags | (rdwr_for_fscache == 1 ?
+ (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE);
+ }
+ if ((oflags & O_ACCMODE) == O_RDWR) {
/* GENERIC_ALL is too much permission to request
can cause unnecessary access denied on create */
/* return GENERIC_ALL; */
- return (GENERIC_READ | GENERIC_WRITE);
+ return flags | GENERIC_READ | GENERIC_WRITE;
}
- return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
- FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
- FILE_READ_DATA);
+ return flags | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
+ FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA |
+ FILE_WRITE_DATA | FILE_READ_DATA;
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -476,7 +495,7 @@ int cifs_posix_open(const char *full_path, struct inode **pinode,
cifs_dbg(FYI, "posix open %s\n", full_path);
- presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ presp_data = kzalloc_obj(FILE_UNIX_BASIC_INFO);
if (presp_data == NULL)
return -ENOMEM;
@@ -571,15 +590,8 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_
*********************************************************************/
disposition = cifs_get_disposition(f_flags);
-
/* BB pass O_SYNC flag through on file attributes .. BB */
-
- /* O_SYNC also has bit for O_DSYNC so following check picks up either */
- if (f_flags & O_SYNC)
- create_options |= CREATE_WRITE_THROUGH;
-
- if (f_flags & O_DIRECT)
- create_options |= CREATE_NO_BUFFER;
+ create_options |= cifs_open_create_options(f_flags, create_options);
retry_open:
oparms = (struct cifs_open_parms) {
@@ -660,11 +672,11 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct cifs_tcon *tcon = tlink_tcon(tlink);
struct TCP_Server_Info *server = tcon->ses->server;
- cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+ cfile = kzalloc_obj(struct cifsFileInfo);
if (cfile == NULL)
return cfile;
- fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL);
+ fdlocks = kzalloc_obj(struct cifs_fid_locks);
if (!fdlocks) {
kfree(cfile);
return NULL;
@@ -690,6 +702,7 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
cfile->f_flags = file->f_flags;
cfile->invalidHandle = false;
cfile->deferred_close_scheduled = false;
+ cfile->status_file_deleted = file->f_flags & O_TMPFILE;
cfile->tlink = cifs_get_tlink(tlink);
INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
INIT_WORK(&cfile->put, cifsFileInfo_put_work);
@@ -698,8 +711,6 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
mutex_init(&cfile->fh_mutex);
spin_lock_init(&cfile->file_info_lock);
- cifs_sb_active(inode->i_sb);
-
/*
* If the server returned a read oplock and we have mandatory brlocks,
* set oplock level to None.
@@ -718,14 +729,16 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
oplock = fid->pending_open->oplock;
list_del(&fid->pending_open->olist);
- fid->purge_cache = false;
- server->ops->set_fid(cfile, fid, oplock);
-
list_add(&cfile->tlist, &tcon->openFileList);
atomic_inc(&tcon->num_local_opens);
/* if readable file instance put first in list*/
spin_lock(&cinode->open_file_lock);
+ if (file->f_flags & O_TMPFILE)
+ set_bit(CIFS_INO_TMPFILE, &cinode->flags);
+ fid->purge_cache = false;
+ server->ops->set_fid(cfile, fid, oplock);
+
if (file->f_mode & FMODE_READ)
list_add(&cfile->flist, &cinode->openFileList);
else
@@ -754,7 +767,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
struct inode *inode = d_inode(cifs_file->dentry);
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifsLockInfo *li, *tmp;
- struct super_block *sb = inode->i_sb;
/*
* Delete any outstanding lock records. We'll lose them when the file
@@ -772,7 +784,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
cifs_put_tlink(cifs_file->tlink);
dput(cifs_file->dentry);
- cifs_sb_deactive(sb);
kfree(cifs_file->symlink_target);
kfree(cifs_file);
}
@@ -893,7 +904,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
* close because it may cause a error when we open this file
* again and get at least level II oplock.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_STRICT_IO)
set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
cifs_set_oplock_level(cifsi, 0);
}
@@ -939,30 +950,89 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
}
}
-int cifs_open(struct inode *inode, struct file *file)
+int cifs_file_flush(const unsigned int xid, struct inode *inode,
+ struct cifsFileInfo *cfile)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_tcon *tcon;
+ int rc;
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOSSYNC)
+ return 0;
+
+ if (cfile && (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE)) {
+ tcon = tlink_tcon(cfile->tlink);
+ return tcon->ses->server->ops->flush(xid, tcon,
+ &cfile->fid);
+ }
+ rc = cifs_get_writable_file(CIFS_I(inode), FIND_ANY, &cfile);
+ if (!rc) {
+ tcon = tlink_tcon(cfile->tlink);
+ rc = tcon->ses->server->ops->flush(xid, tcon, &cfile->fid);
+ cifsFileInfo_put(cfile);
+ } else if (rc == -EBADF) {
+ rc = 0;
+ }
+ return rc;
+}
+
+static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
{
- int rc = -EACCES;
- unsigned int xid;
- __u32 oplock;
- struct cifs_sb_info *cifs_sb;
+ struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
+ struct inode *inode = d_inode(dentry);
+ struct cifsFileInfo *cfile = NULL;
struct TCP_Server_Info *server;
struct cifs_tcon *tcon;
- struct tcon_link *tlink;
+ int rc;
+
+ rc = filemap_write_and_wait(inode->i_mapping);
+ if (is_interrupt_error(rc))
+ return -ERESTARTSYS;
+ mapping_set_error(inode->i_mapping, rc);
+
+ cfile = find_writable_file(cinode, FIND_FSUID_ONLY);
+ rc = cifs_file_flush(xid, inode, cfile);
+ if (!rc) {
+ if (cfile) {
+ tcon = tlink_tcon(cfile->tlink);
+ server = tcon->ses->server;
+ rc = server->ops->set_file_size(xid, tcon,
+ cfile, 0, false);
+ }
+ if (!rc) {
+ netfs_resize_file(&cinode->netfs, 0, true);
+ cifs_setsize(inode, 0);
+ }
+ }
+ if (cfile)
+ cifsFileInfo_put(cfile);
+ return rc;
+}
+
+int cifs_open(struct inode *inode, struct file *file)
+
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_open_info_data data = {};
struct cifsFileInfo *cfile = NULL;
- void *page;
- const char *full_path;
+ struct TCP_Server_Info *server;
+ struct cifs_pending_open open;
bool posix_open_ok = false;
struct cifs_fid fid = {};
- struct cifs_pending_open open;
- struct cifs_open_info_data data = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ const char *full_path;
+ unsigned int sbflags;
+ int rc = -EACCES;
+ unsigned int xid;
+ __u32 oplock;
+ void *page;
xid = get_xid();
- cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
free_xid(xid);
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
}
tlink = cifs_sb_tlink(cifs_sb);
@@ -983,36 +1053,48 @@ int cifs_open(struct inode *inode, struct file *file)
cifs_dbg(FYI, "inode = 0x%p file flags are 0x%x for %s\n",
inode, file->f_flags, full_path);
- if (file->f_flags & O_DIRECT &&
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
file->f_op = &cifs_file_direct_nobrl_ops;
else
file->f_op = &cifs_file_direct_ops;
}
+ if (file->f_flags & O_TRUNC) {
+ rc = cifs_do_truncate(xid, file_dentry(file));
+ if (rc)
+ goto out;
+ }
+
/* Get the cached handle as SMB2 close is deferred */
if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) {
- rc = cifs_get_writable_path(tcon, full_path, FIND_WR_FSUID_ONLY, &cfile);
+ rc = __cifs_get_writable_file(CIFS_I(inode),
+ FIND_FSUID_ONLY |
+ FIND_NO_PENDING_DELETE |
+ FIND_OPEN_FLAGS,
+ file->f_flags, &cfile);
} else {
- rc = cifs_get_readable_path(tcon, full_path, &cfile);
+ cfile = __find_readable_file(CIFS_I(inode),
+ FIND_NO_PENDING_DELETE |
+ FIND_OPEN_FLAGS,
+ file->f_flags);
+ rc = cfile ? 0 : -ENOENT;
}
if (rc == 0) {
- if (file->f_flags == cfile->f_flags) {
- file->private_data = cfile;
- spin_lock(&CIFS_I(inode)->deferred_lock);
- cifs_del_deferred_close(cfile);
- spin_unlock(&CIFS_I(inode)->deferred_lock);
- goto use_cache;
- } else {
- _cifsFileInfo_put(cfile, true, false);
- }
- } else {
- /* hard link on the defeered close file */
- rc = cifs_get_hardlink_path(tcon, inode, file);
- if (rc)
- cifs_close_deferred_file(CIFS_I(inode));
- }
+ trace_smb3_open_cached(xid, tcon->tid, tcon->ses->Suid,
+ cfile->fid.persistent_fid,
+ file->f_flags, cfile->f_flags);
+ file->private_data = cfile;
+ spin_lock(&CIFS_I(inode)->deferred_lock);
+ cifs_del_deferred_close(cfile);
+ spin_unlock(&CIFS_I(inode)->deferred_lock);
+ goto use_cache;
+ }
+ /* hard link on the deferred close file */
+ rc = cifs_get_hardlink_path(tcon, inode, file);
+ if (rc)
+ cifs_close_deferred_file(CIFS_I(inode));
if (server->oplocks)
oplock = REQ_OPLOCK;
@@ -1124,7 +1206,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cinode);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
@@ -1137,7 +1219,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
rc = cifs_push_posix_locks(cfile);
else
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -1233,13 +1315,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
rdwr_for_fscache = 1;
desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache);
-
- /* O_SYNC also has bit for O_DSYNC so following check picks up either */
- if (cfile->f_flags & O_SYNC)
- create_options |= CREATE_WRITE_THROUGH;
-
- if (cfile->f_flags & O_DIRECT)
- create_options |= CREATE_NO_BUFFER;
+ create_options |= cifs_open_create_options(cfile->f_flags,
+ create_options);
if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &cfile->fid);
@@ -1325,7 +1402,8 @@ reopen_success:
oplock = 0;
}
- server->ops->set_fid(cfile, &cfile->fid, oplock);
+ scoped_guard(spinlock, &cinode->open_file_lock)
+ server->ops->set_fid(cfile, &cfile->fid, oplock);
if (oparms.reconnect)
cifs_relock_file(cfile);
@@ -1352,11 +1430,11 @@ smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cinode = CIFS_I(inode);
+ unsigned int oplock = READ_ONCE(cinode->oplock);
- return (cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose &&
- (cinode->oplock == CIFS_CACHE_RHW_FLG ||
- cinode->oplock == CIFS_CACHE_RH_FLG) &&
- !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags));
+ return cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose &&
+ (oplock == CIFS_CACHE_RHW_FLG || oplock == CIFS_CACHE_RH_FLG) &&
+ !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags);
}
@@ -1366,13 +1444,14 @@ int cifs_close(struct inode *inode, struct file *file)
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_deferred_close *dclose;
+ struct cifs_tcon *tcon;
cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE);
if (file->private_data != NULL) {
cfile = file->private_data;
file->private_data = NULL;
- dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
+ dclose = kmalloc_obj(struct cifs_deferred_close);
if ((cfile->status_file_deleted == false) &&
(smb2_can_defer_close(inode, dclose))) {
if (test_and_clear_bit(NETFS_ICTX_MODIFIED_ATTR, &cinode->netfs.flags)) {
@@ -1392,6 +1471,10 @@ int cifs_close(struct inode *inode, struct file *file)
cifsFileInfo_get(cfile);
} else {
/* Deferred close for files */
+ tcon = tlink_tcon(cfile->tlink);
+ trace_smb3_close_cached(tcon->tid, tcon->ses->Suid,
+ cfile->fid.persistent_fid,
+ cifs_sb->ctx->closetimeo);
queue_delayed_work(deferredclose_wq,
&cfile->deferred, cifs_sb->ctx->closetimeo);
cfile->deferred_close_scheduled = true;
@@ -1496,7 +1579,7 @@ static struct cifsLockInfo *
cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 flags)
{
struct cifsLockInfo *lock =
- kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
+ kmalloc_obj(struct cifsLockInfo);
if (!lock)
return lock;
lock->offset = offset;
@@ -1555,6 +1638,9 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
continue;
if (conf_lock)
*conf_lock = li;
+ trace_smb3_lock_conflict(cfile->fid.persistent_fid,
+ offset, length, type,
+ li->offset, li->length, li->type, li->pid);
return true;
}
return false;
@@ -1636,7 +1722,7 @@ cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
*/
static int
cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
- bool wait)
+ bool wait, unsigned int xid)
{
struct cifsLockInfo *conf_lock;
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
@@ -1651,7 +1737,13 @@ try_again:
lock->type, lock->flags, &conf_lock,
CIFS_LOCK_OP);
if (!exist && cinode->can_cache_brlcks) {
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+
list_add_tail(&lock->llist, &cfile->llist->locks);
+ trace_smb3_lock_cached(xid, cfile->fid.persistent_fid,
+ tcon->tid, tcon->ses->Suid,
+ lock->offset, lock->length,
+ lock->type, 1, 0);
up_write(&cinode->lock_sem);
return rc;
}
@@ -1767,7 +1859,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
PAGE_SIZE);
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
- buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ buf = kzalloc_objs(LOCKING_ANDX_RANGE, max_num);
if (!buf) {
free_xid(xid);
return -ENOMEM;
@@ -1859,7 +1951,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
* protects locking operations of this inode.
*/
for (i = 0; i < count; i++) {
- lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
+ lck = kmalloc_obj(struct lock_to_push);
if (!lck) {
rc = -ENOMEM;
goto err_out;
@@ -1925,7 +2017,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cinode);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* we are going to update can_cache_brlcks here - need a write access */
@@ -1938,7 +2030,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
rc = cifs_push_posix_locks(cfile);
else
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2143,7 +2235,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
PAGE_SIZE);
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
- buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ buf = kzalloc_objs(LOCKING_ANDX_RANGE, max_num);
if (!buf)
return -ENOMEM;
@@ -2266,7 +2358,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
if (!lock)
return -ENOMEM;
- rc = cifs_lock_add_if(cfile, lock, wait_flag);
+ rc = cifs_lock_add_if(cfile, lock, wait_flag, xid);
if (rc < 0) {
kfree(lock);
return rc;
@@ -2286,7 +2378,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
cifs_zap_mapping(inode);
cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n",
inode);
- CIFS_I(inode)->oplock = 0;
+ cifs_reset_oplock(CIFS_I(inode));
}
rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
@@ -2342,11 +2434,11 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
cifs_read_flock(fl, &type, &lock, &unlock, &wait_flag,
tcon->ses->server);
- cifs_sb = CIFS_FILE_SB(file);
+ cifs_sb = CIFS_SB(file);
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
posix_lck = true;
if (!lock && !unlock) {
@@ -2369,14 +2461,14 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
{
- int rc, xid;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
+ struct cifsFileInfo *cfile;
int lock = 0, unlock = 0;
bool wait_flag = false;
bool posix_lck = false;
- struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
- struct cifsFileInfo *cfile;
__u32 type;
+ int rc, xid;
rc = -EACCES;
xid = get_xid();
@@ -2391,12 +2483,11 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
tcon->ses->server);
- cifs_sb = CIFS_FILE_SB(file);
set_bit(CIFS_INO_CLOSE_ON_LOCK, &CIFS_I(d_inode(cfile->dentry))->flags);
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
posix_lck = true;
/*
* BB add code here to normalize offset and length to account for
@@ -2423,8 +2514,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
return rc;
}
-void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result,
- bool was_async)
+void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result)
{
struct netfs_io_request *wreq = wdata->rreq;
struct netfs_inode *ictx = netfs_inode(wreq->inode);
@@ -2441,17 +2531,40 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t
netfs_resize_file(ictx, wrend, true);
}
- netfs_write_subrequest_terminated(&wdata->subreq, result, was_async);
+ netfs_write_subrequest_terminated(&wdata->subreq, result);
+}
+
+static bool open_flags_match(struct cifsInodeInfo *cinode,
+ unsigned int oflags, unsigned int cflags)
+{
+ struct inode *inode = &cinode->netfs.inode;
+ int crw = 0, orw = 0;
+
+ oflags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+ cflags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+
+ if (cifs_fscache_enabled(inode)) {
+ if (OPEN_FMODE(cflags) & FMODE_WRITE)
+ crw = 1;
+ if (OPEN_FMODE(oflags) & FMODE_WRITE)
+ orw = 1;
+ }
+ if (cifs_convert_flags(oflags, orw) != cifs_convert_flags(cflags, crw))
+ return false;
+
+ return (oflags & (O_SYNC | O_DIRECT)) == (cflags & (O_SYNC | O_DIRECT));
}
-struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
- bool fsuid_only)
+struct cifsFileInfo *__find_readable_file(struct cifsInodeInfo *cifs_inode,
+ unsigned int find_flags,
+ unsigned int open_flags)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode);
+ bool fsuid_only = find_flags & FIND_FSUID_ONLY;
struct cifsFileInfo *open_file = NULL;
- struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb);
/* only filter by fsuid on multiuser mounts */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
fsuid_only = false;
spin_lock(&cifs_inode->open_file_lock);
@@ -2461,6 +2574,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
continue;
+ if ((find_flags & FIND_NO_PENDING_DELETE) &&
+ open_file->status_file_deleted)
+ continue;
+ if ((find_flags & FIND_OPEN_FLAGS) &&
+ !open_flags_match(cifs_inode, open_flags,
+ open_file->f_flags))
+ continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
if ((!open_file->invalidHandle)) {
/* found a good file */
@@ -2479,18 +2599,17 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
}
/* Return -EBADF if no handle is found and general rc otherwise */
-int
-cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
- struct cifsFileInfo **ret_file)
+int __cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
+ unsigned int find_flags, unsigned int open_flags,
+ struct cifsFileInfo **ret_file)
{
struct cifsFileInfo *open_file, *inv_file = NULL;
+ bool fsuid_only, with_delete;
struct cifs_sb_info *cifs_sb;
bool any_available = false;
- int rc = -EBADF;
unsigned int refind = 0;
- bool fsuid_only = flags & FIND_WR_FSUID_ONLY;
- bool with_delete = flags & FIND_WR_WITH_DELETE;
*ret_file = NULL;
+ int rc = -EBADF;
/*
* Having a null inode here (because mapping->host was set to zero by
@@ -2504,10 +2623,15 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
return rc;
}
- cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb);
+ if (test_bit(CIFS_INO_TMPFILE, &cifs_inode->flags))
+ find_flags = FIND_ANY;
+
+ cifs_sb = CIFS_SB(cifs_inode);
+ with_delete = find_flags & FIND_WITH_DELETE;
+ fsuid_only = find_flags & FIND_FSUID_ONLY;
/* only filter by fsuid on multiuser mounts */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
fsuid_only = false;
spin_lock(&cifs_inode->open_file_lock);
@@ -2523,6 +2647,13 @@ refind_writable:
continue;
if (with_delete && !(open_file->fid.access & DELETE))
continue;
+ if ((find_flags & FIND_NO_PENDING_DELETE) &&
+ open_file->status_file_deleted)
+ continue;
+ if ((find_flags & FIND_OPEN_FLAGS) &&
+ !open_flags_match(cifs_inode, open_flags,
+ open_file->f_flags))
+ continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
if (!open_file->invalidHandle) {
/* found a good writable file */
@@ -2582,16 +2713,19 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, int flags)
return cfile;
}
-int
-cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
- int flags,
- struct cifsFileInfo **ret_file)
+int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+ struct inode *inode, int flags,
+ struct cifsFileInfo **ret_file)
{
struct cifsFileInfo *cfile;
- void *page = alloc_dentry_path();
+ void *page;
*ret_file = NULL;
+ if (inode)
+ return cifs_get_writable_file(CIFS_I(inode), flags, ret_file);
+
+ page = alloc_dentry_path();
spin_lock(&tcon->open_file_lock);
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
struct cifsInodeInfo *cinode;
@@ -2639,7 +2773,7 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
cinode = CIFS_I(d_inode(cfile->dentry));
spin_unlock(&tcon->open_file_lock);
free_dentry_path(page);
- *ret_file = find_readable_file(cinode, 0);
+ *ret_file = find_readable_file(cinode, FIND_ANY);
return *ret_file ? 0 : -ENOENT;
}
@@ -2654,13 +2788,10 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
int datasync)
{
- unsigned int xid;
- int rc = 0;
- struct cifs_tcon *tcon;
- struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file_inode(file);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ unsigned int xid;
+ int rc;
rc = file_write_and_wait_range(file, start, end);
if (rc) {
@@ -2668,39 +2799,15 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
return rc;
}
- xid = get_xid();
-
- cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n",
- file, datasync);
+ cifs_dbg(FYI, "%s: name=%pD datasync=0x%x\n", __func__, file, datasync);
if (!CIFS_CACHE_READ(CIFS_I(inode))) {
rc = cifs_zap_mapping(inode);
- if (rc) {
- cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc);
- rc = 0; /* don't care about it in fsync */
- }
+ cifs_dbg(FYI, "%s: invalidate mapping: rc = %d\n", __func__, rc);
}
- tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
- server = tcon->ses->server;
- if (server->ops->flush == NULL) {
- rc = -ENOSYS;
- goto strict_fsync_exit;
- }
-
- if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
- smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
- if (smbfile) {
- rc = server->ops->flush(xid, tcon, &smbfile->fid);
- cifsFileInfo_put(smbfile);
- } else
- cifs_dbg(FYI, "ignore fsync for file not open for write\n");
- } else
- rc = server->ops->flush(xid, tcon, &smbfile->fid);
- }
-
-strict_fsync_exit:
+ xid = get_xid();
+ rc = cifs_file_flush(xid, inode, smbfile);
free_xid(xid);
return rc;
}
@@ -2716,7 +2823,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file_inode(file);
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
rc = file_write_and_wait_range(file, start, end);
if (rc) {
@@ -2730,7 +2837,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
file, datasync);
tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOSSYNC)) {
server = tcon->ses->server;
if (server->ops->flush == NULL) {
rc = -ENOSYS;
@@ -2738,7 +2845,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
- smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
+ smbfile = find_writable_file(CIFS_I(inode), FIND_ANY);
if (smbfile) {
rc = server->ops->flush(xid, tcon, &smbfile->fid);
cifsFileInfo_put(smbfile);
@@ -2782,7 +2889,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
struct inode *inode = file->f_mapping->host;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
ssize_t rc;
rc = netfs_start_io_write(inode);
@@ -2799,7 +2906,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
if (rc <= 0)
goto out;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) &&
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) &&
(cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from),
server->vals->exclusive_lock_type, 0,
NULL, CIFS_WRITE_OP))) {
@@ -2822,7 +2929,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct cifsInodeInfo *cinode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)
iocb->ki_filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
@@ -2835,7 +2942,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
if (CIFS_CACHE_WRITE(cinode)) {
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
written = netfs_file_write_iter(iocb, from);
goto out;
}
@@ -2860,7 +2967,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
cifs_zap_mapping(inode);
cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n",
inode);
- cinode->oplock = 0;
+ cifs_reset_oplock(cinode);
}
out:
cifs_put_writer(cinode);
@@ -2896,7 +3003,7 @@ ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
cifs_dbg(FYI,
"Set no oplock for inode=%p after a write operation\n",
inode);
- cinode->oplock = 0;
+ cifs_reset_oplock(cinode);
}
return written;
}
@@ -2923,7 +3030,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct cifsInodeInfo *cinode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)
iocb->ki_filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
@@ -2940,7 +3047,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
if (!CIFS_CACHE_READ(cinode))
return netfs_unbuffered_read_iter(iocb, to);
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) {
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0) {
if (iocb->ki_flags & IOCB_DIRECT)
return netfs_unbuffered_read_iter(iocb, to);
return netfs_buffered_read_iter(iocb, to);
@@ -2992,38 +3099,38 @@ static const struct vm_operations_struct cifs_file_vm_ops = {
.page_mkwrite = cifs_page_mkwrite,
};
-int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
+int cifs_file_strict_mmap_prepare(struct vm_area_desc *desc)
{
int xid, rc = 0;
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(desc->file);
xid = get_xid();
if (!CIFS_CACHE_READ(CIFS_I(inode)))
rc = cifs_zap_mapping(inode);
if (!rc)
- rc = generic_file_mmap(file, vma);
+ rc = generic_file_mmap_prepare(desc);
if (!rc)
- vma->vm_ops = &cifs_file_vm_ops;
+ desc->vm_ops = &cifs_file_vm_ops;
free_xid(xid);
return rc;
}
-int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
+int cifs_file_mmap_prepare(struct vm_area_desc *desc)
{
int rc, xid;
xid = get_xid();
- rc = cifs_revalidate_file(file);
+ rc = cifs_revalidate_file(desc->file);
if (rc)
cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
rc);
if (!rc)
- rc = generic_file_mmap(file, vma);
+ rc = generic_file_mmap_prepare(desc);
if (!rc)
- vma->vm_ops = &cifs_file_vm_ops;
+ desc->vm_ops = &cifs_file_vm_ops;
free_xid(xid);
return rc;
@@ -3059,10 +3166,9 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
if (is_inode_writable(cifsInode) ||
((cifsInode->oplock & CIFS_CACHE_RW_FLG) != 0 && from_readdir)) {
/* This inode is open for write at least once */
- struct cifs_sb_info *cifs_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cifsInode);
- cifs_sb = CIFS_SB(cifsInode->netfs.inode.i_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_DIRECT_IO) {
/* since no page cache to corrupt on directio
we can change size safely */
return true;
@@ -3081,11 +3187,14 @@ void cifs_oplock_break(struct work_struct *work)
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
struct inode *inode = d_inode(cfile->dentry);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct super_block *sb = inode->i_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsInodeInfo *cinode = CIFS_I(inode);
+ bool cache_read, cache_write, cache_handle;
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
struct tcon_link *tlink;
+ unsigned int oplock;
int rc = 0;
bool purge_cache = false, oplock_break_cancelled;
__u64 persistent_fid, volatile_fid;
@@ -3100,29 +3209,40 @@ void cifs_oplock_break(struct work_struct *work)
tcon = tlink_tcon(tlink);
server = tcon->ses->server;
- server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
- cfile->oplock_epoch, &purge_cache);
+ scoped_guard(spinlock, &cinode->open_file_lock) {
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
+ cfile->oplock_epoch, &purge_cache);
+ oplock = READ_ONCE(cinode->oplock);
+ cache_read = (oplock & CIFS_CACHE_READ_FLG) ||
+ (sbflags & CIFS_MOUNT_RO_CACHE);
+ cache_write = (oplock & CIFS_CACHE_WRITE_FLG) ||
+ (sbflags & CIFS_MOUNT_RW_CACHE);
+ cache_handle = oplock & CIFS_CACHE_HANDLE_FLG;
+ }
- if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) &&
- cifs_has_mand_locks(cinode)) {
+ if (!cache_write && cache_read && cifs_has_mand_locks(cinode)) {
cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n",
inode);
- cinode->oplock = 0;
+ cifs_reset_oplock(cinode);
+ oplock = 0;
+ cache_read = cache_write = cache_handle = false;
}
if (S_ISREG(inode->i_mode)) {
- if (CIFS_CACHE_READ(cinode))
+ if (cache_read)
break_lease(inode, O_RDONLY);
else
break_lease(inode, O_WRONLY);
rc = filemap_fdatawrite(inode->i_mapping);
- if (!CIFS_CACHE_READ(cinode) || purge_cache) {
+ if (!cache_read || purge_cache) {
rc = filemap_fdatawait(inode->i_mapping);
mapping_set_error(inode->i_mapping, rc);
cifs_zap_mapping(inode);
}
cifs_dbg(FYI, "Oplock flush inode %p rc %d\n", inode, rc);
- if (CIFS_CACHE_WRITE(cinode))
+ if (cache_write)
goto oplock_break_ack;
}
@@ -3137,7 +3257,7 @@ oplock_break_ack:
* So, new open will not use cached handle.
*/
- if (!CIFS_CACHE_HANDLE(cinode) && !list_empty(&cinode->deferred_closes))
+ if (!cache_handle && !list_empty(&cinode->deferred_closes))
cifs_close_deferred_file(cinode);
persistent_fid = cfile->fid.persistent_fid;
@@ -3155,7 +3275,8 @@ oplock_break_ack:
if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) {
spin_unlock(&cinode->open_file_lock);
rc = server->ops->oplock_response(tcon, persistent_fid,
- volatile_fid, net_fid, cinode);
+ volatile_fid, net_fid,
+ cinode, oplock);
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
} else
spin_unlock(&cinode->open_file_lock);
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 2980941b9667..b9544eb0381b 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -26,7 +26,6 @@
#include <linux/parser.h>
#include <linux/utsname.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
@@ -81,7 +80,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_flag_no("forcegid", Opt_forcegid),
fsparam_flag("noblocksend", Opt_noblocksend),
fsparam_flag("noautotune", Opt_noautotune),
- fsparam_flag("nolease", Opt_nolease),
+ fsparam_flag_no("lease", Opt_lease),
fsparam_flag_no("hard", Opt_hard),
fsparam_flag_no("soft", Opt_soft),
fsparam_flag_no("perm", Opt_perm),
@@ -505,7 +504,7 @@ cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_contex
case Smb_20:
cifs_errorf(fc, "vers=2.0 mount not permitted when legacy dialects disabled\n");
return 1;
-#endif /* CIFS_ALLOW_INSECURE_LEGACY */
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
case Smb_21:
ctx->ops = &smb21_operations;
ctx->vals = &smb21_values;
@@ -589,6 +588,10 @@ char *cifs_sanitize_prepath(char *prepath, gfp_t gfp)
while (IS_DELIM(*cursor1))
cursor1++;
+ /* exit in case of only delimiters */
+ if (!*cursor1)
+ return NULL;
+
/* copy the first letter */
*cursor2 = *cursor1;
@@ -659,13 +662,17 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
/* make sure we have a valid UNC double delimiter prefix */
len = strspn(devname, delims);
- if (len != 2)
+ if (len != 2) {
+ cifs_dbg(VFS, "UNC: path must begin with // or \\\\\n");
return -EINVAL;
+ }
/* find delimiter between host and sharename */
pos = strpbrk(devname + 2, delims);
- if (!pos)
+ if (!pos) {
+ cifs_dbg(VFS, "UNC: missing delimiter between hostname and share name\n");
return -EINVAL;
+ }
/* record the server hostname */
kfree(ctx->server_hostname);
@@ -678,8 +685,10 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
/* now go until next delimiter or end of string */
len = strcspn(pos, delims);
- if (!len)
+ if (!len) {
+ cifs_dbg(VFS, "UNC: missing share name\n");
return -EINVAL;
+ }
/* move "pos" up to delimiter or NULL */
pos += len;
@@ -711,12 +720,54 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
return 0;
}
+static int smb3_handle_conflicting_options(struct fs_context *fc)
+{
+ struct smb3_fs_context *ctx = smb3_fc2context(fc);
+
+ if (ctx->multichannel_specified) {
+ if (ctx->multichannel) {
+ if (!ctx->max_channels_specified) {
+ ctx->max_channels = 2;
+ } else if (ctx->max_channels == 1) {
+ cifs_errorf(fc,
+ "max_channels must be greater than 1 when multichannel is enabled\n");
+ return -EINVAL;
+ }
+ } else {
+ if (!ctx->max_channels_specified) {
+ ctx->max_channels = 1;
+ } else if (ctx->max_channels > 1) {
+ cifs_errorf(fc,
+ "max_channels must be equal to 1 when multichannel is disabled\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ if (ctx->max_channels_specified) {
+ if (ctx->max_channels > 1)
+ ctx->multichannel = true;
+ else
+ ctx->multichannel = false;
+ } else {
+ ctx->multichannel = false;
+ ctx->max_channels = 1;
+ }
+ }
+
+ //resetting default values as remount doesn't initialize fs_context again
+ ctx->multichannel_specified = false;
+ ctx->max_channels_specified = false;
+
+ return 0;
+}
+
static void smb3_fs_context_free(struct fs_context *fc);
static int smb3_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param);
static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
void *data);
static int smb3_get_tree(struct fs_context *fc);
+static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels);
static int smb3_reconfigure(struct fs_context *fc);
static const struct fs_context_operations smb3_fs_context_ops = {
@@ -773,21 +824,18 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
}
- len = 0;
value = strchr(key, '=');
if (value) {
if (value == key)
continue;
*value++ = 0;
- len = strlen(value);
}
- ret = vfs_parse_fs_string(fc, key, value, len);
+ ret = vfs_parse_fs_string(fc, key, value);
if (ret < 0)
break;
}
-
- return ret;
+ return ret ?: smb3_handle_conflicting_options(fc);
}
/*
@@ -1015,12 +1063,29 @@ int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_se
return 0;
}
+/*
+ * smb3_sync_ses_chan_max - Synchronize the session's maximum channel count
+ * @ses: pointer to the old CIFS session structure
+ * @max_channels: new maximum number of channels to allow
+ *
+ * Updates the session's chan_max field to the new value, protecting the update
+ * with the session's channel lock. This should be called whenever the maximum
+ * allowed channels for a session changes (e.g., after a remount or reconfigure).
+ */
+static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels)
+{
+ spin_lock(&ses->chan_lock);
+ ses->chan_max = max_channels;
+ spin_unlock(&ses->chan_lock);
+}
+
static int smb3_reconfigure(struct fs_context *fc)
{
struct smb3_fs_context *ctx = smb3_fc2context(fc);
struct dentry *root = fc->root;
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
+ unsigned int rsize = ctx->rsize, wsize = ctx->wsize;
char *new_password = NULL, *new_password2 = NULL;
bool need_recon = false;
int rc;
@@ -1081,6 +1146,8 @@ static int smb3_reconfigure(struct fs_context *fc)
rc = smb3_sync_session_ctx_passwords(cifs_sb, ses);
if (rc) {
mutex_unlock(&ses->session_mutex);
+ kfree_sensitive(new_password);
+ kfree_sensitive(new_password2);
return rc;
}
@@ -1096,18 +1163,47 @@ static int smb3_reconfigure(struct fs_context *fc)
ses->password2 = new_password2;
}
- mutex_unlock(&ses->session_mutex);
+ /*
+ * If multichannel or max_channels has changed, update the session's channels accordingly.
+ * This may add or remove channels to match the new configuration.
+ */
+ if ((ctx->multichannel != cifs_sb->ctx->multichannel) ||
+ (ctx->max_channels != cifs_sb->ctx->max_channels)) {
+
+ /* Synchronize ses->chan_max with the new mount context */
+ smb3_sync_ses_chan_max(ses, ctx->max_channels);
+ /* Now update the session's channels to match the new configuration */
+ /* Prevent concurrent scaling operations */
+ spin_lock(&ses->ses_lock);
+ if (ses->flags & CIFS_SES_FLAG_SCALE_CHANNELS) {
+ spin_unlock(&ses->ses_lock);
+ mutex_unlock(&ses->session_mutex);
+ return -EINVAL;
+ }
+ ses->flags |= CIFS_SES_FLAG_SCALE_CHANNELS;
+ spin_unlock(&ses->ses_lock);
+
+ mutex_unlock(&ses->session_mutex);
+
+ rc = smb3_update_ses_channels(ses, ses->server,
+ false /* from_reconnect */,
+ false /* disable_mchan */);
+
+ /* Clear scaling flag after operation */
+ spin_lock(&ses->ses_lock);
+ ses->flags &= ~CIFS_SES_FLAG_SCALE_CHANNELS;
+ spin_unlock(&ses->ses_lock);
+ } else {
+ mutex_unlock(&ses->session_mutex);
+ }
STEAL_STRING(cifs_sb, ctx, domainname);
STEAL_STRING(cifs_sb, ctx, nodename);
STEAL_STRING(cifs_sb, ctx, iocharset);
/* if rsize or wsize not passed in on remount, use previous values */
- if (ctx->rsize == 0)
- ctx->rsize = cifs_sb->ctx->rsize;
- if (ctx->wsize == 0)
- ctx->wsize = cifs_sb->ctx->wsize;
-
+ ctx->rsize = rsize ? CIFS_ALIGN_RSIZE(fc, rsize) : cifs_sb->ctx->rsize;
+ ctx->wsize = wsize ? CIFS_ALIGN_WSIZE(fc, wsize) : cifs_sb->ctx->wsize;
smb3_cleanup_fs_context_contents(cifs_sb->ctx);
rc = smb3_fs_context_dup(cifs_sb->ctx, ctx);
@@ -1244,8 +1340,8 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
case Opt_noautotune:
ctx->noautotune = 1;
break;
- case Opt_nolease:
- ctx->no_lease = 1;
+ case Opt_lease:
+ ctx->no_lease = result.negated;
break;
case Opt_nosparse:
ctx->no_sparse = 1;
@@ -1254,15 +1350,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->nodelete = 1;
break;
case Opt_multichannel:
- if (result.negated) {
+ ctx->multichannel_specified = true;
+ if (result.negated)
ctx->multichannel = false;
- ctx->max_channels = 1;
- } else {
+ else
ctx->multichannel = true;
- /* if number of channels not specified, default to 2 */
- if (ctx->max_channels < 2)
- ctx->max_channels = 2;
- }
break;
case Opt_uid:
ctx->linux_uid = result.uid;
@@ -1312,7 +1404,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
__func__);
goto cifs_parse_mount_err;
}
- ctx->bsize = result.uint_32;
+ ctx->bsize = CIFS_ALIGN_BSIZE(fc, result.uint_32);
ctx->got_bsize = true;
break;
case Opt_rasize:
@@ -1336,24 +1428,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->rasize = result.uint_32;
break;
case Opt_rsize:
- ctx->rsize = result.uint_32;
+ ctx->rsize = CIFS_ALIGN_RSIZE(fc, result.uint_32);
ctx->got_rsize = true;
ctx->vol_rsize = ctx->rsize;
break;
case Opt_wsize:
- ctx->wsize = result.uint_32;
+ ctx->wsize = CIFS_ALIGN_WSIZE(fc, result.uint_32);
ctx->got_wsize = true;
- if (ctx->wsize % PAGE_SIZE != 0) {
- ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
- if (ctx->wsize == 0) {
- ctx->wsize = PAGE_SIZE;
- cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
- } else {
- cifs_dbg(VFS,
- "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
- ctx->wsize, PAGE_SIZE);
- }
- }
ctx->vol_wsize = ctx->wsize;
break;
case Opt_acregmax:
@@ -1409,15 +1490,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->max_credits = result.uint_32;
break;
case Opt_max_channels:
+ ctx->max_channels_specified = true;
if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) {
cifs_errorf(fc, "%s: Invalid max_channels value, needs to be 1-%d\n",
__func__, CIFS_MAX_CHANNELS);
goto cifs_parse_mount_err;
}
ctx->max_channels = result.uint_32;
- /* If more than one channel requested ... they want multichan */
- if (result.uint_32 > 1)
- ctx->multichannel = true;
break;
case Opt_max_cached_dirs:
if (result.uint_32 < 1) {
@@ -1450,12 +1529,14 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
cifs_errorf(fc, "Unknown error parsing devname\n");
goto cifs_parse_mount_err;
}
+ kfree(ctx->source);
ctx->source = smb3_fs_context_fullpath(ctx, '/');
if (IS_ERR(ctx->source)) {
ctx->source = NULL;
cifs_errorf(fc, "OOM when copying UNC string\n");
goto cifs_parse_mount_err;
}
+ kfree(fc->source);
fc->source = kstrdup(ctx->source, GFP_KERNEL);
if (fc->source == NULL) {
cifs_errorf(fc, "OOM when copying UNC string\n");
@@ -1483,40 +1564,26 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
break;
}
- if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) >
+ if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) ==
CIFS_MAX_USERNAME_LEN) {
pr_warn("username too long\n");
goto cifs_parse_mount_err;
}
- ctx->username = kstrdup(param->string, GFP_KERNEL);
- if (ctx->username == NULL) {
- cifs_errorf(fc, "OOM when copying username string\n");
- goto cifs_parse_mount_err;
- }
+ ctx->username = no_free_ptr(param->string);
break;
case Opt_pass:
kfree_sensitive(ctx->password);
ctx->password = NULL;
if (strlen(param->string) == 0)
break;
-
- ctx->password = kstrdup(param->string, GFP_KERNEL);
- if (ctx->password == NULL) {
- cifs_errorf(fc, "OOM when copying password string\n");
- goto cifs_parse_mount_err;
- }
+ ctx->password = no_free_ptr(param->string);
break;
case Opt_pass2:
kfree_sensitive(ctx->password2);
ctx->password2 = NULL;
if (strlen(param->string) == 0)
break;
-
- ctx->password2 = kstrdup(param->string, GFP_KERNEL);
- if (ctx->password2 == NULL) {
- cifs_errorf(fc, "OOM when copying password2 string\n");
- goto cifs_parse_mount_err;
- }
+ ctx->password2 = no_free_ptr(param->string);
break;
case Opt_ip:
if (strlen(param->string) == 0) {
@@ -1539,11 +1606,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
}
kfree(ctx->domainname);
- ctx->domainname = kstrdup(param->string, GFP_KERNEL);
- if (ctx->domainname == NULL) {
- cifs_errorf(fc, "OOM when copying domainname string\n");
- goto cifs_parse_mount_err;
- }
+ ctx->domainname = no_free_ptr(param->string);
cifs_dbg(FYI, "Domain name set\n");
break;
case Opt_srcaddr:
@@ -1563,11 +1626,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
if (strncasecmp(param->string, "default", 7) != 0) {
kfree(ctx->iocharset);
- ctx->iocharset = kstrdup(param->string, GFP_KERNEL);
- if (ctx->iocharset == NULL) {
- cifs_errorf(fc, "OOM when copying iocharset string\n");
- goto cifs_parse_mount_err;
- }
+ ctx->iocharset = no_free_ptr(param->string);
}
/* if iocharset not set then load_nls_default
* is used by caller
@@ -1687,6 +1746,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
pr_warn_once("conflicting posix mount options specified\n");
ctx->linux_ext = 1;
ctx->no_linux_ext = 0;
+ ctx->nonativesocket = 1; /* POSIX mounts use NFS style reparse points */
}
break;
case Opt_nocase:
@@ -1837,10 +1897,14 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
cifs_errorf(fc, "symlinkroot mount options must be absolute path\n");
goto cifs_parse_mount_err;
}
- kfree(ctx->symlinkroot);
- ctx->symlinkroot = kstrdup(param->string, GFP_KERNEL);
- if (!ctx->symlinkroot)
+ if (strnlen(param->string, PATH_MAX) == PATH_MAX) {
+ cifs_errorf(fc, "symlinkroot path too long (max path length: %u)\n",
+ PATH_MAX - 1);
goto cifs_parse_mount_err;
+ }
+ kfree(ctx->symlinkroot);
+ ctx->symlinkroot = param->string;
+ param->string = NULL;
break;
}
/* case Opt_ignore: - is ignored as expected ... */
@@ -1850,13 +1914,6 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
goto cifs_parse_mount_err;
}
- /*
- * By default resolve all native absolute symlinks relative to "/mnt/".
- * Same default has drvfs driver running in WSL for resolving SMB shares.
- */
- if (!ctx->symlinkroot)
- ctx->symlinkroot = kstrdup("/mnt/", GFP_KERNEL);
-
return 0;
cifs_parse_mount_err:
@@ -1864,34 +1921,20 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->password = NULL;
kfree_sensitive(ctx->password2);
ctx->password2 = NULL;
+ kfree(ctx->source);
+ ctx->source = NULL;
+ kfree(fc->source);
+ fc->source = NULL;
return -EINVAL;
}
-enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb)
-{
- if (cifs_sb->ctx->symlink_type == CIFS_SYMLINK_TYPE_DEFAULT) {
- if (cifs_sb->ctx->mfsymlinks)
- return CIFS_SYMLINK_TYPE_MFSYMLINKS;
- else if (cifs_sb->ctx->sfu_emul)
- return CIFS_SYMLINK_TYPE_SFU;
- else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
- return CIFS_SYMLINK_TYPE_UNIX;
- else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
- return CIFS_SYMLINK_TYPE_NATIVE;
- else
- return CIFS_SYMLINK_TYPE_NONE;
- } else {
- return cifs_sb->ctx->symlink_type;
- }
-}
-
int smb3_init_fs_context(struct fs_context *fc)
{
struct smb3_fs_context *ctx;
char *nodename = utsname()->nodename;
int i;
- ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
+ ctx = kzalloc_obj(struct smb3_fs_context);
if (unlikely(!ctx))
return -ENOMEM;
@@ -1957,12 +2000,14 @@ int smb3_init_fs_context(struct fs_context *fc)
/* default to no multichannel (single server connection) */
ctx->multichannel = false;
+ ctx->multichannel_specified = false;
+ ctx->max_channels_specified = false;
ctx->max_channels = 1;
ctx->backupuid_specified = false; /* no backup intent for a user */
ctx->backupgid_specified = false; /* no backup intent for a group */
- ctx->retrans = 1;
+ ctx->retrans = 0;
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT;
ctx->nonativesocket = 0;
@@ -2027,161 +2072,160 @@ smb3_cleanup_fs_context(struct smb3_fs_context *ctx)
kfree(ctx);
}
-void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
+unsigned int smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct smb3_fs_context *ctx = cifs_sb->ctx;
if (ctx->nodfs)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
+ sbflags |= CIFS_MOUNT_NO_DFS;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_DFS;
+ sbflags &= ~CIFS_MOUNT_NO_DFS;
if (ctx->noperm)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
+ sbflags |= CIFS_MOUNT_NO_PERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_PERM;
+ sbflags &= ~CIFS_MOUNT_NO_PERM;
if (ctx->setuids)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+ sbflags |= CIFS_MOUNT_SET_UID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SET_UID;
+ sbflags &= ~CIFS_MOUNT_SET_UID;
if (ctx->setuidfromacl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
+ sbflags |= CIFS_MOUNT_UID_FROM_ACL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UID_FROM_ACL;
+ sbflags &= ~CIFS_MOUNT_UID_FROM_ACL;
if (ctx->server_ino)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+ sbflags |= CIFS_MOUNT_SERVER_INUM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+ sbflags &= ~CIFS_MOUNT_SERVER_INUM;
if (ctx->remap)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
+ sbflags |= CIFS_MOUNT_MAP_SFM_CHR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SFM_CHR;
+ sbflags &= ~CIFS_MOUNT_MAP_SFM_CHR;
if (ctx->sfu_remap)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+ sbflags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
+ sbflags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
if (ctx->no_xattr)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+ sbflags |= CIFS_MOUNT_NO_XATTR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_XATTR;
+ sbflags &= ~CIFS_MOUNT_NO_XATTR;
if (ctx->sfu_emul)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+ sbflags |= CIFS_MOUNT_UNX_EMUL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UNX_EMUL;
+ sbflags &= ~CIFS_MOUNT_UNX_EMUL;
if (ctx->nobrl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+ sbflags |= CIFS_MOUNT_NO_BRL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_BRL;
+ sbflags &= ~CIFS_MOUNT_NO_BRL;
if (ctx->nohandlecache)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
+ sbflags |= CIFS_MOUNT_NO_HANDLE_CACHE;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
+ sbflags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
if (ctx->nostrictsync)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
+ sbflags |= CIFS_MOUNT_NOSSYNC;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOSSYNC;
+ sbflags &= ~CIFS_MOUNT_NOSSYNC;
if (ctx->mand_lock)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
+ sbflags |= CIFS_MOUNT_NOPOSIXBRL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOPOSIXBRL;
+ sbflags &= ~CIFS_MOUNT_NOPOSIXBRL;
if (ctx->rwpidforward)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
+ sbflags |= CIFS_MOUNT_RWPIDFORWARD;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_RWPIDFORWARD;
+ sbflags &= ~CIFS_MOUNT_RWPIDFORWARD;
if (ctx->mode_ace)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
+ sbflags |= CIFS_MOUNT_MODE_FROM_SID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MODE_FROM_SID;
+ sbflags &= ~CIFS_MOUNT_MODE_FROM_SID;
if (ctx->cifs_acl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+ sbflags |= CIFS_MOUNT_CIFS_ACL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_ACL;
+ sbflags &= ~CIFS_MOUNT_CIFS_ACL;
if (ctx->backupuid_specified)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
+ sbflags |= CIFS_MOUNT_CIFS_BACKUPUID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
+ sbflags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
if (ctx->backupgid_specified)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
+ sbflags |= CIFS_MOUNT_CIFS_BACKUPGID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
+ sbflags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
if (ctx->override_uid)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+ sbflags |= CIFS_MOUNT_OVERR_UID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_UID;
+ sbflags &= ~CIFS_MOUNT_OVERR_UID;
if (ctx->override_gid)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+ sbflags |= CIFS_MOUNT_OVERR_GID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_GID;
+ sbflags &= ~CIFS_MOUNT_OVERR_GID;
if (ctx->dynperm)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+ sbflags |= CIFS_MOUNT_DYNPERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DYNPERM;
+ sbflags &= ~CIFS_MOUNT_DYNPERM;
if (ctx->fsc)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
+ sbflags |= CIFS_MOUNT_FSCACHE;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_FSCACHE;
+ sbflags &= ~CIFS_MOUNT_FSCACHE;
if (ctx->multiuser)
- cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
- CIFS_MOUNT_NO_PERM);
+ sbflags |= CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_NO_PERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MULTIUSER;
+ sbflags &= ~CIFS_MOUNT_MULTIUSER;
if (ctx->strict_io)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
+ sbflags |= CIFS_MOUNT_STRICT_IO;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_STRICT_IO;
+ sbflags &= ~CIFS_MOUNT_STRICT_IO;
if (ctx->direct_io)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+ sbflags |= CIFS_MOUNT_DIRECT_IO;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DIRECT_IO;
+ sbflags &= ~CIFS_MOUNT_DIRECT_IO;
if (ctx->mfsymlinks)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
+ sbflags |= CIFS_MOUNT_MF_SYMLINKS;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MF_SYMLINKS;
- if (ctx->mfsymlinks) {
- if (ctx->sfu_emul) {
- /*
- * Our SFU ("Services for Unix") emulation allows now
- * creating new and reading existing SFU symlinks.
- * Older Linux kernel versions were not able to neither
- * read existing nor create new SFU symlinks. But
- * creating and reading SFU style mknod and FIFOs was
- * supported for long time. When "mfsymlinks" and
- * "sfu" are both enabled at the same time, it allows
- * reading both types of symlinks, but will only create
- * them with mfsymlinks format. This allows better
- * Apple compatibility, compatibility with older Linux
- * kernel clients (probably better for Samba too)
- * while still recognizing old Windows style symlinks.
- */
- cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
- }
- }
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
+ sbflags &= ~CIFS_MOUNT_MF_SYMLINKS;
- return;
+ if (ctx->mfsymlinks && ctx->sfu_emul) {
+ /*
+ * Our SFU ("Services for Unix") emulation allows now
+ * creating new and reading existing SFU symlinks.
+ * Older Linux kernel versions were not able to neither
+ * read existing nor create new SFU symlinks. But
+ * creating and reading SFU style mknod and FIFOs was
+ * supported for long time. When "mfsymlinks" and
+ * "sfu" are both enabled at the same time, it allows
+ * reading both types of symlinks, but will only create
+ * them with mfsymlinks format. This allows better
+ * Apple compatibility, compatibility with older Linux
+ * kernel clients (probably better for Samba too)
+ * while still recognizing old Windows style symlinks.
+ */
+ cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
+ }
+ sbflags &= ~CIFS_MOUNT_SHUTDOWN;
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
+ return sbflags;
}
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index d1d29249bcdb..a80a5caff23c 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -20,6 +20,21 @@
cifs_dbg(VFS, fmt, ## __VA_ARGS__); \
} while (0)
+static inline size_t cifs_io_align(struct fs_context *fc,
+ const char *name, size_t size)
+{
+ if (!size || !IS_ALIGNED(size, PAGE_SIZE)) {
+ cifs_errorf(fc, "unaligned %s, making it a multiple of %lu bytes\n",
+ name, PAGE_SIZE);
+ size = umax(round_down(size, PAGE_SIZE), PAGE_SIZE);
+ }
+ return size;
+}
+
+#define CIFS_ALIGN_WSIZE(_fc, _size) cifs_io_align(_fc, "wsize", _size)
+#define CIFS_ALIGN_RSIZE(_fc, _size) cifs_io_align(_fc, "rsize", _size)
+#define CIFS_ALIGN_BSIZE(_fc, _size) cifs_io_align(_fc, "bsize", _size)
+
enum smb_version {
Smb_1 = 1,
Smb_20,
@@ -87,7 +102,7 @@ enum cifs_param {
Opt_forcegid,
Opt_noblocksend,
Opt_noautotune,
- Opt_nolease,
+ Opt_lease,
Opt_nosparse,
Opt_hard,
Opt_soft,
@@ -279,6 +294,8 @@ struct smb3_fs_context {
bool domainauto:1;
bool rdma:1;
bool multichannel:1;
+ bool multichannel_specified:1; /* true if user specified multichannel or nomultichannel */
+ bool max_channels_specified:1; /* true if user specified max_channels */
bool use_client_guid:1;
/* reuse existing guid for multichannel */
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
@@ -326,20 +343,38 @@ struct smb3_fs_context {
extern const struct fs_parameter_spec smb3_fs_parameters[];
-extern enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb);
+static inline enum cifs_symlink_type cifs_symlink_type(struct cifs_sb_info *cifs_sb)
+{
+ bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
+
+ if (cifs_sb->ctx->symlink_type != CIFS_SYMLINK_TYPE_DEFAULT)
+ return cifs_sb->ctx->symlink_type;
+
+ if (cifs_sb->ctx->mfsymlinks)
+ return CIFS_SYMLINK_TYPE_MFSYMLINKS;
+ else if (cifs_sb->ctx->sfu_emul)
+ return CIFS_SYMLINK_TYPE_SFU;
+ else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
+ return posix ? CIFS_SYMLINK_TYPE_NATIVE : CIFS_SYMLINK_TYPE_UNIX;
+ else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
+ return CIFS_SYMLINK_TYPE_NATIVE;
+ return CIFS_SYMLINK_TYPE_NONE;
+}
-extern int smb3_init_fs_context(struct fs_context *fc);
-extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
-extern void smb3_cleanup_fs_context(struct smb3_fs_context *ctx);
+int smb3_init_fs_context(struct fs_context *fc);
+void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
+void smb3_cleanup_fs_context(struct smb3_fs_context *ctx);
static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fc)
{
return fc->fs_private;
}
-extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx);
-extern int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);
-extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
+int smb3_fs_context_dup(struct smb3_fs_context *new_ctx,
+ struct smb3_fs_context *ctx);
+int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb,
+ struct cifs_ses *ses);
+unsigned int smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
/*
* max deferred close timeout (jiffies) - 2^30
@@ -347,7 +382,7 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
#define SMB3_MAX_DCLOSETIMEO (1 << 30)
#define SMB3_DEF_DCLOSETIMEO (1 * HZ) /* even 1 sec enough to help eg open/write/close/open/read */
#define MAX_CACHED_FIDS 16
-extern char *cifs_sanitize_prepath(char *prepath, gfp_t gfp);
+char *cifs_sanitize_prepath(char *prepath, gfp_t gfp);
extern struct mutex cifs_mount_mutex;
@@ -361,4 +396,36 @@ static inline void cifs_mount_unlock(void)
mutex_unlock(&cifs_mount_mutex);
}
+static inline void cifs_negotiate_rsize(struct TCP_Server_Info *server,
+ struct smb3_fs_context *ctx,
+ struct cifs_tcon *tcon)
+{
+ unsigned int size;
+
+ size = umax(server->ops->negotiate_rsize(tcon, ctx), PAGE_SIZE);
+ if (ctx->rsize)
+ size = umax(umin(ctx->rsize, size), PAGE_SIZE);
+ ctx->rsize = round_down(size, PAGE_SIZE);
+}
+
+static inline void cifs_negotiate_wsize(struct TCP_Server_Info *server,
+ struct smb3_fs_context *ctx,
+ struct cifs_tcon *tcon)
+{
+ unsigned int size;
+
+ size = umax(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
+ if (ctx->wsize)
+ size = umax(umin(ctx->wsize, size), PAGE_SIZE);
+ ctx->wsize = round_down(size, PAGE_SIZE);
+}
+
+static inline void cifs_negotiate_iosize(struct TCP_Server_Info *server,
+ struct smb3_fs_context *ctx,
+ struct cifs_tcon *tcon)
+{
+ cifs_negotiate_rsize(server, ctx, tcon);
+ cifs_negotiate_wsize(server, ctx, tcon);
+}
+
#endif
diff --git a/fs/smb/client/fscache.h b/fs/smb/client/fscache.h
index f06cb24f5f3c..3521222886c1 100644
--- a/fs/smb/client/fscache.h
+++ b/fs/smb/client/fscache.h
@@ -38,12 +38,17 @@ struct cifs_fscache_inode_coherency_data {
/*
* fscache.c
*/
-extern int cifs_fscache_get_super_cookie(struct cifs_tcon *);
-extern void cifs_fscache_release_super_cookie(struct cifs_tcon *);
-
-extern void cifs_fscache_get_inode_cookie(struct inode *inode);
-extern void cifs_fscache_release_inode_cookie(struct inode *);
-extern void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update);
+int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon);
+void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon);
+void cifs_fscache_get_inode_cookie(struct inode *inode);
+void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update);
+void cifs_fscache_release_inode_cookie(struct inode *inode);
+int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon);
+void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon);
+
+void cifs_fscache_get_inode_cookie(struct inode *inode);
+void cifs_fscache_release_inode_cookie(struct inode *inode);
+void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update);
static inline
void cifs_fscache_fill_coherency(struct inode *inode,
diff --git a/fs/smb/client/gen_smb1_mapping b/fs/smb/client/gen_smb1_mapping
new file mode 100644
index 000000000000..c2b2939a83c6
--- /dev/null
+++ b/fs/smb/client/gen_smb1_mapping
@@ -0,0 +1,124 @@
+#!/usr/bin/perl -w
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Script to generate SMB1 error mapping tables.
+#
+# Copyright (C) 2026 KylinSoft Co., Ltd. All rights reserved.
+# Author(s): Huiwen He <hehuiwen@kylinos.cn>
+# ChenXiaoSong <chenxiaosong@kylinos.cn>
+#
+use strict;
+
+if ($#ARGV != 1) {
+ print STDERR "Usage: $0 <in-file> <out-file>\n";
+ exit(2);
+}
+
+# Parse input parameters and extract filenames
+my $in_file = $ARGV[0];
+my $out_file = $ARGV[1];
+my $input_name = (split m|/|, $in_file)[-1];
+my $output_name = (split m|/|, $out_file)[-1];
+my $script_name = (split m|/|, $0)[-1];
+my @list = ();
+my %seen = ();
+my $current_class = "";
+
+# Parse annotated entries from the input file
+open(my $in, "<", $in_file) or die "Cannot open $in_file: $!";
+if ($in_file =~ /nterr\.h$/) {
+ while (<$in>) {
+ # Handle backslash line continuation
+ $_ .= <$in> while s/\\\s*\n//;
+
+ # Match #define NT_STATUS_... followed by // CLASS, CODE or /* CLASS, CODE */
+ my $re = qr{^\s*#define\s+(NT_STATUS_[A-Za-z0-9_]+)\s+(.+?)\s*} .
+ qr{(?://\s*|/\*\s*)([A-Z0-9_]+)\s*,\s*([A-Za-z0-9_]+)};
+
+ if (/$re/) {
+ my ($name, $val_str, $class, $code) = ($1, $2, $3, $4);
+
+ # Skip duplicate macro names
+ next if $seen{$name}++;
+
+ # Clean up value string (remove parens, spaces)
+ $val_str =~ s/[\s\(\)]//g;
+ my $val = 0;
+ foreach my $part (split(/\|/, $val_str)) {
+ $val |= hex($part);
+ }
+ push @list, { val => $val, name => $name, class => $class, code => $code };
+ } elsif (/^\s*#define\s+NT_STATUS_.*(?:\/\/|\/\*)/) {
+ # Error if macro has a comment (// or /*) but fails mapping format
+ die "Error: Invalid mapping comment format in $in_file: $_";
+ }
+ }
+} elsif ($in_file =~ /smberr\.h$/) {
+ while (<$in>) {
+ # Handle backslash line continuation
+ $_ .= <$in> while s/\\\s*\n//;
+
+ # Detect current error class from header comments (ERRDOS or ERRSRV)
+ if (/generated with the (\w+) error class/) {
+ $current_class = $1;
+ }
+
+ # Match #define ERR/Err_... <value> followed by // -POSIX_ERR or /* -POSIX_ERR */
+ if (/^\s*#define\s+((?:ERR|Err)[A-Za-z0-9_]+)\s+([0-9a-fA-FxX]+)\s*(?:\/\/|\/\*)\s*(-[A-Z0-9_]+)/) {
+ my ($name, $val_str, $error) = ($1, $2, $3);
+ my $val = ($val_str =~ /^0x/i) ? hex($val_str) : $val_str;
+ push @list, { val => $val, name => $name, error => $error, class => $current_class };
+ } elsif ($current_class && /^\s*#define\s+(?:ERR|Err).*?(?:\/\/|\/\*)/) {
+ # Error if macro has a comment (// or /*) but fails mapping format
+ die "Error: Invalid mapping comment format in $in_file: $_";
+ }
+ }
+}
+close($in);
+
+# Fail if no entries were found to avoid broken builds
+die "Error: No mapping entries found in $in_file\n" unless @list;
+
+# Sort entries numerically by value
+@list = sort { $a->{val} <=> $b->{val} } @list;
+
+# Generate the C mapping table output file
+open(my $out, ">", $out_file) or die "Cannot open $out_file: $!";
+print $out "/* Autogenerated from $input_name by $script_name */\n\n";
+
+if ($output_name eq "smb1_mapping_table.c") {
+ # Generate NT status -> DOS error mapping file
+
+ my $count = scalar @list;
+ my $full_names = "";
+
+ for (my $i = 0; $i < $count; $i++) {
+ my $e = $list[$i];
+ my $val = $e->{val};
+
+ $full_names .= $e->{name};
+
+ # Merge synonyms
+ if ($i < $count - 1 && $list[$i + 1]->{val} == $val) {
+ $full_names .= " or ";
+ next;
+ }
+
+ printf $out "\t{ %s, %s, 0x%08x, \"%s\" },\n", $e->{class}, $e->{code}, $val, $full_names;
+
+ $full_names = "";
+ }
+} elsif ($output_name eq "smb1_err_dos_map.c" || $output_name eq "smb1_err_srv_map.c") {
+ # Generate SMB1 error -> POSIX error mapping file
+
+ # Filtered by exact output filename
+ my $filter = ($output_name eq "smb1_err_dos_map.c") ? "ERRDOS" : "ERRSRV";
+ foreach my $e (@list) {
+ if (!$filter || $e->{class} eq $filter) {
+ printf $out "\t{%s, %s},\n", $e->{name}, $e->{error};
+ }
+ }
+} else {
+ die "Error: Unsupported output target: $output_name\n";
+}
+close($out);
diff --git a/fs/smb/client/gen_smb2_mapping b/fs/smb/client/gen_smb2_mapping
new file mode 100644
index 000000000000..eb9fa727ddd8
--- /dev/null
+++ b/fs/smb/client/gen_smb2_mapping
@@ -0,0 +1,86 @@
+#!/usr/bin/perl -w
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Generate an SMB2 status -> error mapping table,
+# sorted by NT status code (cpu-endian, ascending).
+#
+# Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+use strict;
+
+if ($#ARGV != 1) {
+ print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
+ exit(2);
+}
+
+my %statuses = ();
+my @list = ();
+
+#
+# Read the file
+#
+open IN_FILE, "<$ARGV[0]" || die;
+while (<IN_FILE>) {
+ chomp;
+
+ if (m!^#define\s*([A-Za-z0-9_]+)\s+cpu_to_le32[(]([0-9a-fA-Fx]+)[)]\s+//\s+([-A-Z0-9_]+)!) {
+ my $status = $1;
+ my $code = $2;
+ my $ncode = hex($2);
+ my $error = $3;
+ my $s;
+
+ next if ($status =~ /^STATUS_SEVERITY/);
+
+ die "Duplicate status $status"
+ if exists($statuses{$status});
+
+ my %s = (
+ status => $status,
+ code => $code,
+ ncode => $ncode,
+ error => $error
+ );
+ $statuses{$status} = \%s;
+ push @list, \%s;
+ }
+}
+close IN_FILE || die;
+
+
+@list = sort( { $a->{ncode} <=> $b->{ncode} } @list);
+
+open OUT_FILE, ">$ARGV[1]" || die;
+my $list_size = scalar @list;
+my $full_status = "";
+for (my $i = 0; $i < $list_size; $i++) {
+ my $entry = $list[$i];
+ my $status = $entry->{status};
+ my $code = $entry->{code};
+ my $ncode = $entry->{ncode};
+ my $error = $entry->{error};
+
+ next if ($ncode == 0);
+
+ $full_status .= $status;
+ # There may be synonyms
+ if ($i < $list_size - 1) {
+ my $next_entry = $list[$i + 1];
+ my $next_ncode = $next_entry->{ncode};
+ if ($next_ncode == $ncode) {
+ $full_status .= " or ";
+ next;
+ }
+ }
+
+ my $pad = " ";
+ if (length($full_status) < 40) {
+ my $n = 40 - length($full_status);
+ $pad = "\t" x ((($n-1) / 8) + 1);
+ }
+ print(OUT_FILE "{ $code, $error, \"$full_status\" },\n");
+
+ $full_status = "";
+}
+close OUT_FILE || die;
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 75be4b46bc6f..16a5310155d5 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -6,6 +6,7 @@
*
*/
#include <linux/fs.h>
+#include <linux/fs_struct.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
@@ -15,7 +16,6 @@
#include <linux/fiemap.h>
#include <asm/div64.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "smb2proto.h"
@@ -40,32 +40,33 @@ static void cifs_set_netfs_context(struct inode *inode)
static void cifs_set_ops(struct inode *inode)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct netfs_inode *ictx = netfs_inode(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
inode->i_op = &cifs_file_inode_ops;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (sbflags & CIFS_MOUNT_DIRECT_IO) {
set_bit(NETFS_ICTX_UNBUFFERED, &ictx->flags);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (sbflags & CIFS_MOUNT_STRICT_IO) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_strict_nobrl_ops;
else
inode->i_fop = &cifs_file_strict_ops;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
else { /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
}
/* check if server can support readahead */
- if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
- PAGE_SIZE + MAX_CIFS_HDR_SIZE)
+ if (tcon->ses->server->max_read < PAGE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
inode->i_data.a_ops = &cifs_addr_ops;
@@ -101,7 +102,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
cifs_dbg(FYI, "%s: revalidating inode %llu\n",
__func__, cifs_i->uniqueid);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
cifs_dbg(FYI, "%s: inode %llu is new\n",
__func__, cifs_i->uniqueid);
return;
@@ -146,7 +147,7 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
*/
if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
/* only provide fake values on a new inode */
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
set_nlink(inode, 2);
else
@@ -167,12 +168,12 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- if (!(inode->i_state & I_NEW) &&
+ if (!(inode_state_read_once(inode) & I_NEW) &&
unlikely(inode_wrong_type(inode, fattr->cf_mode))) {
CIFS_I(inode)->time = 0; /* force reval */
return -ESTALE;
}
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
CIFS_I(inode)->netfs.zero_point = fattr->cf_eof;
cifs_revalidate_cache(inode, fattr);
@@ -194,8 +195,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
inode->i_gid = fattr->cf_gid;
/* if dynperm is set, don't clobber existing mode */
- if (inode->i_state & I_NEW ||
- !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
+ if ((inode_state_read(inode) & I_NEW) ||
+ !(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_DYNPERM))
inode->i_mode = fattr->cf_mode;
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
@@ -218,13 +219,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
*/
if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) {
i_size_write(inode, fattr->cf_eof);
-
- /*
- * i_blocks is not related to (i_size / i_blksize),
- * but instead 512 byte (2**9) size is required for
- * calculating num blocks.
- */
- inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
+ inode->i_blocks = CIFS_INO_BLOCKS(fattr->cf_bytes);
}
if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) {
@@ -236,7 +231,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
inode->i_flags |= S_AUTOMOUNT;
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
cifs_set_netfs_context(inode);
cifs_set_ops(inode);
}
@@ -248,10 +243,8 @@ cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
- return;
-
- fattr->cf_uniqueid = iunique(sb, ROOT_I);
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM))
+ fattr->cf_uniqueid = iunique(sb, ROOT_I);
}
/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
@@ -259,6 +252,8 @@ void
cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags;
+
memset(fattr, 0, sizeof(*fattr));
fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
@@ -317,8 +312,9 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
break;
}
+ sbflags = cifs_sb_flags(cifs_sb);
fattr->cf_uid = cifs_sb->ctx->linux_uid;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) {
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID)) {
u64 id = le64_to_cpu(info->Uid);
if (id < ((uid_t)-1)) {
kuid_t uid = make_kuid(&init_user_ns, id);
@@ -328,7 +324,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
}
fattr->cf_gid = cifs_sb->ctx->linux_gid;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID)) {
u64 id = le64_to_cpu(info->Gid);
if (id < ((gid_t)-1)) {
kgid_t gid = make_kgid(&init_user_ns, id);
@@ -382,7 +378,7 @@ static int update_inode_info(struct super_block *sb,
*
* If file type or uniqueid is different, return error.
*/
- if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ if (unlikely((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM) &&
CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
CIFS_I(*inode)->time = 0; /* force reval */
return -ESTALE;
@@ -468,7 +464,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path,
cifs_fill_uniqueid(sb, fattr);
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1081,7 +1077,7 @@ cifs_backup_query_path_info(int xid,
else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0)
info.info_level = SMB_FIND_FILE_INFO_STANDARD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+ else if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM)
info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
else /* no srvino useful for fallback to some netapp */
info.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
@@ -1109,7 +1105,7 @@ static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_blo
struct TCP_Server_Info *server = tcon->ses->server;
int rc;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM)) {
if (*inode)
fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
else
@@ -1263,14 +1259,15 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
struct inode **inode,
const char *full_path)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_open_info_data tmp_data = {};
- struct cifs_tcon *tcon;
+ void *smb1_backup_rsp_buf = NULL;
struct TCP_Server_Info *server;
+ struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- void *smb1_backup_rsp_buf = NULL;
- int rc = 0;
+ unsigned int sbflags;
int tmprc = 0;
+ int rc = 0;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -1328,7 +1325,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
/* for easier reading */
FILE_ALL_INFO *fi;
FILE_DIRECTORY_INFO *fdi;
- SEARCH_ID_FULL_DIR_INFO *si;
+ FILE_ID_FULL_DIR_INFO *si;
rc = cifs_backup_query_path_info(xid, tcon, sb,
full_path,
@@ -1339,7 +1336,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
move_cifs_info_to_smb2(&data->fi, fi);
fdi = (FILE_DIRECTORY_INFO *)fi;
- si = (SEARCH_ID_FULL_DIR_INFO *)fi;
+ si = (FILE_ID_FULL_DIR_INFO *)fi;
cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
@@ -1370,16 +1367,17 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
handle_mnt_opt:
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+ sbflags = cifs_sb_flags(cifs_sb);
/* query for SFU type info if supported and needed */
if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
+ (sbflags & CIFS_MOUNT_UNX_EMUL)) {
tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
if (tmprc)
cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
}
/* fill in 0777 bits from ACL */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
+ if (sbflags & CIFS_MOUNT_MODE_FROM_SID) {
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
true, full_path, fid);
if (rc == -EREMOTE)
@@ -1389,7 +1387,7 @@ handle_mnt_opt:
__func__, rc);
goto out;
}
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
+ } else if (sbflags & CIFS_MOUNT_CIFS_ACL) {
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
false, full_path, fid);
if (rc == -EREMOTE)
@@ -1399,7 +1397,7 @@ handle_mnt_opt:
__func__, rc);
goto out;
}
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ } else if (sbflags & CIFS_MOUNT_UNX_EMUL)
/* fill in remaining high mode bits e.g. SUID, VTX */
cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
else if (!(tcon->posix_extensions))
@@ -1409,7 +1407,7 @@ handle_mnt_opt:
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1509,7 +1507,7 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
* 3. Tweak fattr based on mount options
*/
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1597,7 +1595,7 @@ inode_has_hashed_dentries(struct inode *inode)
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+ for_each_alias(dentry, inode) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
@@ -1638,7 +1636,7 @@ retry_iget5_locked:
cifs_fattr_to_inode(inode, fattr, false);
if (sb->s_flags & SB_NOATIME)
inode->i_flags |= S_NOATIME | S_NOCMTIME;
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
inode->i_ino = hash;
cifs_fscache_get_inode_cookie(inode);
unlock_new_inode(inode);
@@ -1660,7 +1658,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
int len;
int rc;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH)
&& cifs_sb->prepath) {
len = strlen(cifs_sb->prepath);
path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
@@ -1841,7 +1839,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
if (dosattr != origattr) {
- info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
+ info_buf = kzalloc_obj(*info_buf);
if (info_buf == NULL) {
rc = -ENOMEM;
goto out_close;
@@ -1931,7 +1929,7 @@ cifs_drop_nlink(struct inode *inode)
* but will return the EACCES to the caller. Note that the VFS does not call
* unlink on negative dentries currently.
*/
-int cifs_unlink(struct inode *dir, struct dentry *dentry)
+static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyrename)
{
int rc = 0;
unsigned int xid;
@@ -1943,14 +1941,23 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ __u32 dosattr = 0, origattr = 0;
struct TCP_Server_Info *server;
struct iattr *attrs = NULL;
- __u32 dosattr = 0, origattr = 0;
+ bool rehash = false;
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
+
+ /* Unhash dentry in advance to prevent any concurrent opens */
+ spin_lock(&dentry->d_lock);
+ if (!d_unhashed(dentry)) {
+ __d_drop(dentry);
+ rehash = true;
+ }
+ spin_unlock(&dentry->d_lock);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -1975,7 +1982,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
}
netfs_wait_for_outstanding_io(inode);
- cifs_close_deferred_file_under_dentry(tcon, full_path);
+ cifs_close_deferred_file_under_dentry(tcon, dentry);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -1994,7 +2001,24 @@ retry_std_delete:
goto psx_del_no_retry;
}
- rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
+ /* For SMB2+, if the file is open, we always perform a silly rename.
+ *
+ * We check for d_count() right after calling
+ * cifs_close_deferred_file_under_dentry() to make sure that the
+ * dentry's refcount gets dropped in case the file had any deferred
+ * close.
+ */
+ if (!sillyrename && server->vals->protocol_id > SMB10_PROT_ID) {
+ spin_lock(&dentry->d_lock);
+ if (d_count(dentry) > 1)
+ sillyrename = true;
+ spin_unlock(&dentry->d_lock);
+ }
+
+ if (sillyrename)
+ rc = -EBUSY;
+ else
+ rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
psx_del_no_retry:
if (!rc) {
@@ -2003,7 +2027,8 @@ psx_del_no_retry:
cifs_drop_nlink(inode);
}
} else if (rc == -ENOENT) {
- d_drop(dentry);
+ if (simple_positive(dentry))
+ d_delete(dentry);
} else if (rc == -EBUSY) {
if (server->ops->rename_pending_delete) {
rc = server->ops->rename_pending_delete(full_path,
@@ -2014,7 +2039,7 @@ psx_del_no_retry:
}
}
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
- attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
+ attrs = kzalloc_obj(*attrs);
if (attrs == NULL) {
rc = -ENOMEM;
goto out_reval;
@@ -2056,16 +2081,24 @@ unlink_out:
kfree(attrs);
free_xid(xid);
cifs_put_tlink(tlink);
+ if (rehash)
+ d_rehash(dentry);
return rc;
}
+int cifs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ return __cifs_unlink(dir, dentry, false);
+}
+
static int
cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
const char *full_path, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon, const unsigned int xid)
{
- int rc = 0;
struct inode *inode = NULL;
+ unsigned int sbflags;
+ int rc = 0;
if (tcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&inode, full_path,
@@ -2105,6 +2138,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
if (parent->i_mode & S_ISGID)
mode |= S_ISGID;
+ sbflags = cifs_sb_flags(cifs_sb);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = {
@@ -2114,7 +2148,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
.mtime = NO_CHANGE_64,
.device = 0,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
if (parent->i_mode & S_ISGID)
args.gid = parent->i_gid;
@@ -2132,14 +2166,14 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
{
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
struct TCP_Server_Info *server = tcon->ses->server;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ if (!(sbflags & CIFS_MOUNT_CIFS_ACL) &&
(mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
tcon, xid);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
inode->i_mode = (mode | S_IFDIR);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
inode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID)
inode->i_gid = parent->i_gid;
@@ -2163,7 +2197,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
struct inode *newinode = NULL;
struct cifs_fattr fattr;
- info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ info = kzalloc_obj(FILE_UNIX_BASIC_INFO);
if (info == NULL) {
rc = -ENOMEM;
goto posix_mkdir_out;
@@ -2233,7 +2267,7 @@ struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return ERR_PTR(-EIO);
+ return ERR_PTR(smb_EIO(smb_eio_trace_forced_shutdown));
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return ERR_CAST(tlink);
@@ -2319,7 +2353,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_forced_shutdown);
goto rmdir_exit;
}
@@ -2346,14 +2380,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
cifs_put_tlink(tlink);
+ cifsInode = CIFS_I(d_inode(direntry));
+
if (!rc) {
+ set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags);
spin_lock(&d_inode(direntry)->i_lock);
i_size_write(d_inode(direntry), 0);
clear_nlink(d_inode(direntry));
spin_unlock(&d_inode(direntry)->i_lock);
}
- cifsInode = CIFS_I(d_inode(direntry));
/* force revalidate to go get info when needed */
cifsInode->time = 0;
@@ -2395,8 +2431,10 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
tcon = tlink_tcon(tlink);
server = tcon->ses->server;
- if (!server->ops->rename)
- return -ENOSYS;
+ if (!server->ops->rename) {
+ rc = -ENOSYS;
+ goto do_rename_exit;
+ }
/* try path-based rename first */
rc = server->ops->rename(xid, tcon, from_dentry,
@@ -2458,10 +2496,12 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
struct dentry *target_dentry, unsigned int flags)
{
const char *from_name, *to_name;
+ struct TCP_Server_Info *server;
void *page1, *page2;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ bool rehash = false;
unsigned int xid;
int rc, tmprc;
int retry_count = 0;
@@ -2475,12 +2515,24 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
cifs_sb = CIFS_SB(source_dir->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
+
+ /*
+ * Prevent any concurrent opens on the target by unhashing the dentry.
+ * VFS already unhashes the target when renaming directories.
+ */
+ if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) {
+ if (!d_unhashed(target_dentry)) {
+ d_drop(target_dentry);
+ rehash = true;
+ }
+ }
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
page1 = alloc_dentry_path();
page2 = alloc_dentry_path();
@@ -2498,10 +2550,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
goto cifs_rename_exit;
}
- cifs_close_deferred_file_under_dentry(tcon, from_name);
+ cifs_close_deferred_file_under_dentry(tcon, source_dentry);
if (d_inode(target_dentry) != NULL) {
netfs_wait_for_outstanding_io(d_inode(target_dentry));
- cifs_close_deferred_file_under_dentry(tcon, to_name);
+ cifs_close_deferred_file_under_dentry(tcon, target_dentry);
}
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
@@ -2518,6 +2570,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
}
}
+ if (!rc)
+ rehash = false;
/*
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
*/
@@ -2531,8 +2585,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
* with unix extensions enabled.
*/
info_buf_source =
- kmalloc_array(2, sizeof(FILE_UNIX_BASIC_INFO),
- GFP_KERNEL);
+ kmalloc_objs(FILE_UNIX_BASIC_INFO, 2);
if (info_buf_source == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
@@ -2565,23 +2618,61 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
unlink_target:
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
-
- /* Try unlinking the target dentry if it's not negative */
- if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) {
- if (d_is_dir(target_dentry))
- tmprc = cifs_rmdir(target_dir, target_dentry);
- else
- tmprc = cifs_unlink(target_dir, target_dentry);
- if (tmprc)
- goto cifs_rename_exit;
- rc = cifs_do_rename(xid, source_dentry, from_name,
- target_dentry, to_name);
+ if (d_really_is_positive(target_dentry)) {
+ if (!rc) {
+ struct inode *inode = d_inode(target_dentry);
+ /*
+ * Samba and ksmbd servers allow renaming a target
+ * directory that is open, so make sure to update
+ * ->i_nlink and then mark it as delete pending.
+ */
+ if (S_ISDIR(inode->i_mode)) {
+ drop_cached_dir_by_name(xid, tcon, to_name, cifs_sb);
+ spin_lock(&inode->i_lock);
+ i_size_write(inode, 0);
+ clear_nlink(inode);
+ spin_unlock(&inode->i_lock);
+ set_bit(CIFS_INO_DELETE_PENDING, &CIFS_I(inode)->flags);
+ CIFS_I(inode)->time = 0; /* force reval */
+ inode_set_ctime_current(inode);
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ }
+ } else if (rc == -EACCES || rc == -EEXIST) {
+ /*
+ * Rename failed, possibly due to a busy target.
+ * Retry it by unliking the target first.
+ */
+ if (d_is_dir(target_dentry)) {
+ tmprc = cifs_rmdir(target_dir, target_dentry);
+ } else {
+ tmprc = __cifs_unlink(target_dir, target_dentry,
+ server->vals->protocol_id > SMB10_PROT_ID);
+ }
+ if (tmprc) {
+ /*
+ * Some servers will return STATUS_ACCESS_DENIED
+ * or STATUS_DIRECTORY_NOT_EMPTY when failing to
+ * rename a non-empty directory. Make sure to
+ * propagate the appropriate error back to
+ * userspace.
+ */
+ if (tmprc == -EEXIST || tmprc == -ENOTEMPTY)
+ rc = tmprc;
+ goto cifs_rename_exit;
+ }
+ rc = cifs_do_rename(xid, source_dentry, from_name,
+ target_dentry, to_name);
+ if (!rc)
+ rehash = false;
+ }
}
/* force revalidate to go get info when needed */
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
cifs_rename_exit:
+ if (rehash)
+ d_rehash(target_dentry);
kfree(info_buf_source);
free_dentry_path(page2);
free_dentry_path(page1);
@@ -2595,10 +2686,13 @@ cifs_dentry_needs_reval(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct cached_fid *cfid = NULL;
+ if (test_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags) ||
+ test_bit(CIFS_INO_TMPFILE, &cifs_i->flags))
+ return false;
if (cifs_i->time == 0)
return true;
@@ -2609,7 +2703,7 @@ cifs_dentry_needs_reval(struct dentry *dentry)
return true;
if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) {
- if (cfid->time && cifs_i->time > cfid->time) {
+ if (cifs_i->time > cfid->time) {
close_cached_dir(cfid);
return false;
}
@@ -2634,7 +2728,7 @@ cifs_dentry_needs_reval(struct dentry *dentry)
}
/* hardlinked files w/ noserverino get "special" treatment */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM) &&
S_ISREG(inode->i_mode) && inode->i_nlink != 1)
return true;
@@ -2659,10 +2753,10 @@ cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
int
cifs_revalidate_mapping(struct inode *inode)
{
- int rc;
struct cifsInodeInfo *cifs_inode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
unsigned long *flags = &cifs_inode->flags;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ int rc;
/* swapfiles are not supposed to be shared */
if (IS_SWAPFILE(inode))
@@ -2675,7 +2769,7 @@ cifs_revalidate_mapping(struct inode *inode)
if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) {
/* for cache=singleclient, do not invalidate */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RW_CACHE)
goto skip_invalidate;
cifs_inode->netfs.zero_point = cifs_inode->netfs.remote_i_size;
@@ -2749,7 +2843,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
}
cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
- full_path, inode, inode->i_count.counter,
+ full_path, inode, icount_read(inode),
dentry, cifs_get_time(dentry), jiffies);
again:
@@ -2799,14 +2893,15 @@ int cifs_revalidate_dentry(struct dentry *dentry)
int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int flags)
{
- struct dentry *dentry = path->dentry;
- struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(path->dentry);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry);
+ unsigned int sbflags;
int rc;
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
/*
* We need to be sure that all dirty pages are written and the server
@@ -2859,12 +2954,13 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
* enabled, and the admin hasn't overridden them, set the ownership
* to the fsuid/fsgid of the current process.
*/
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
- !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((sbflags & CIFS_MOUNT_MULTIUSER) &&
+ !(sbflags & CIFS_MOUNT_CIFS_ACL) &&
!tcon->unix_ext) {
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID))
stat->uid = current_fsuid();
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID))
stat->gid = current_fsgid();
}
return 0;
@@ -2881,7 +2977,7 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
int rc;
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
/*
* We need to be sure that all dirty pages are written as they
@@ -2896,7 +2992,7 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
}
}
- cfile = find_readable_file(cifs_i, false);
+ cfile = find_readable_file(cifs_i, FIND_ANY);
if (cfile == NULL)
return -EINVAL;
@@ -2912,28 +3008,30 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
void cifs_setsize(struct inode *inode, loff_t offset)
{
- struct cifsInodeInfo *cifs_i = CIFS_I(inode);
-
spin_lock(&inode->i_lock);
i_size_write(inode, offset);
+ /*
+ * Until we can query the server for actual allocation size,
+ * this is best estimate we have for blocks allocated for a file.
+ */
+ inode->i_blocks = CIFS_INO_BLOCKS(offset);
spin_unlock(&inode->i_lock);
-
- /* Cached inode must be refreshed on truncate */
- cifs_i->time = 0;
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
truncate_pagecache(inode, offset);
+ netfs_wait_for_outstanding_io(inode);
}
-static int
-cifs_set_file_size(struct inode *inode, struct iattr *attrs,
- unsigned int xid, const char *full_path, struct dentry *dentry)
+int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
+ const char *full_path, struct cifsFileInfo *open_file,
+ loff_t size)
{
- int rc;
- struct cifsFileInfo *open_file;
- struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct inode *inode = d_inode(dentry);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon = NULL;
struct TCP_Server_Info *server;
+ int rc = -EINVAL;
/*
* To avoid spurious oplock breaks from server, in the case of
@@ -2944,19 +3042,25 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
* writebehind data than the SMB timeout for the SetPathInfo
* request would allow
*/
- open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
- if (open_file) {
+ if (open_file && (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE)) {
tcon = tlink_tcon(open_file->tlink);
server = tcon->ses->server;
- if (server->ops->set_file_size)
- rc = server->ops->set_file_size(xid, tcon, open_file,
- attrs->ia_size, false);
- else
- rc = -ENOSYS;
- cifsFileInfo_put(open_file);
- cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc);
- } else
- rc = -EINVAL;
+ rc = server->ops->set_file_size(xid, tcon,
+ open_file,
+ size, false);
+ cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc);
+ } else {
+ open_file = find_writable_file(cifsInode, FIND_FSUID_ONLY);
+ if (open_file) {
+ tcon = tlink_tcon(open_file->tlink);
+ server = tcon->ses->server;
+ rc = server->ops->set_file_size(xid, tcon,
+ open_file,
+ size, false);
+ cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc);
+ cifsFileInfo_put(open_file);
+ }
+ }
if (!rc)
goto set_size_out;
@@ -2974,36 +3078,15 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
* valid, writeable file handle for it was found or because there was
* an error setting it by handle.
*/
- if (server->ops->set_path_size)
- rc = server->ops->set_path_size(xid, tcon, full_path,
- attrs->ia_size, cifs_sb, false, dentry);
- else
- rc = -ENOSYS;
- cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc);
-
- if (tlink)
- cifs_put_tlink(tlink);
+ rc = server->ops->set_path_size(xid, tcon, full_path, size,
+ cifs_sb, false, dentry);
+ cifs_dbg(FYI, "%s: SetEOF by path (setattrs) rc = %d\n", __func__, rc);
+ cifs_put_tlink(tlink);
set_size_out:
if (rc == 0) {
- netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
- cifs_setsize(inode, attrs->ia_size);
- /*
- * i_blocks is not related to (i_size / i_blksize), but instead
- * 512 byte (2**9) size is required for calculating num blocks.
- * Until we can query the server for actual allocation size,
- * this is best estimate we have for blocks allocated for a file
- * Number of blocks must be rounded up so size 1 is not 0 blocks
- */
- inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
-
- /*
- * The man page of truncate says if the size changed,
- * then the st_ctime and st_mtime fields for the file
- * are updated.
- */
- attrs->ia_ctime = attrs->ia_mtime = current_time(inode);
- attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME;
+ netfs_resize_file(&cifsInode->netfs, size, true);
+ cifs_setsize(inode, size);
}
return rc;
@@ -3019,24 +3102,27 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
void *page = alloc_dentry_path();
struct inode *inode = d_inode(direntry);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
struct cifs_unix_set_info_args *args = NULL;
- struct cifsFileInfo *open_file;
+ struct cifsFileInfo *open_file = NULL;
cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n",
direntry, attrs->ia_valid);
xid = get_xid();
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
if (rc < 0)
goto out;
+ if (attrs->ia_valid & ATTR_FILE)
+ open_file = attrs->ia_file->private_data;
+
full_path = build_path_from_dentry(direntry, page);
if (IS_ERR(full_path)) {
rc = PTR_ERR(full_path);
@@ -3064,16 +3150,23 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
rc = 0;
if (attrs->ia_valid & ATTR_SIZE) {
- rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
+ rc = cifs_file_set_size(xid, direntry, full_path,
+ open_file, attrs->ia_size);
if (rc != 0)
goto out;
+ /*
+ * Avoid setting timestamps on the server for ftruncate(2) to
+ * prevent it from disabling automatic timestamp updates as per
+ * MS-FSA 2.1.4.17.
+ */
+ attrs->ia_valid &= ~(ATTR_CTIME | ATTR_MTIME);
}
/* skip mode change if it's just for clearing setuid/setgid */
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
attrs->ia_valid &= ~ATTR_MODE;
- args = kmalloc(sizeof(*args), GFP_KERNEL);
+ args = kmalloc_obj(*args);
if (args == NULL) {
rc = -ENOMEM;
goto out;
@@ -3111,14 +3204,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args->ctime = NO_CHANGE_64;
args->device = 0;
- open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
- if (open_file) {
- u16 nfid = open_file->fid.netfid;
- u32 npid = open_file->pid;
+ rc = -EINVAL;
+ if (open_file && (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE)) {
pTcon = tlink_tcon(open_file->tlink);
- rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
- cifsFileInfo_put(open_file);
+ rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args,
+ open_file->fid.netfid,
+ open_file->pid);
} else {
+ open_file = find_writable_file(cifsInode, FIND_FSUID_ONLY);
+ if (open_file) {
+ pTcon = tlink_tcon(open_file->tlink);
+ rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args,
+ open_file->fid.netfid,
+ open_file->pid);
+ cifsFileInfo_put(open_file);
+ }
+ }
+
+ if (rc) {
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
@@ -3126,8 +3229,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
}
pTcon = tlink_tcon(tlink);
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
- cifs_sb->local_nls,
- cifs_remap(cifs_sb));
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
cifs_put_tlink(tlink);
}
@@ -3163,33 +3266,35 @@ out:
static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
{
- unsigned int xid;
- kuid_t uid = INVALID_UID;
- kgid_t gid = INVALID_GID;
struct inode *inode = d_inode(direntry);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
- struct cifsFileInfo *wfile;
- struct cifs_tcon *tcon;
- const char *full_path;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+ struct cifsFileInfo *cfile = NULL;
void *page = alloc_dentry_path();
- int rc = -EACCES;
- __u32 dosattr = 0;
__u64 mode = NO_CHANGE_64;
- bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
+ kuid_t uid = INVALID_UID;
+ kgid_t gid = INVALID_GID;
+ const char *full_path;
+ __u32 dosattr = 0;
+ int rc = -EACCES;
+ unsigned int xid;
xid = get_xid();
cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n",
direntry, attrs->ia_valid);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (sbflags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
if (rc < 0)
goto cifs_setattr_exit;
+ if (attrs->ia_valid & ATTR_FILE)
+ cfile = attrs->ia_file->private_data;
+
full_path = build_path_from_dentry(direntry, page);
if (IS_ERR(full_path)) {
rc = PTR_ERR(full_path);
@@ -3216,25 +3321,23 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
rc = 0;
- if ((attrs->ia_valid & ATTR_MTIME) &&
- !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
- rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
- if (!rc) {
- tcon = tlink_tcon(wfile->tlink);
- rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
- cifsFileInfo_put(wfile);
- if (rc)
- goto cifs_setattr_exit;
- } else if (rc != -EBADF)
+ if (attrs->ia_valid & ATTR_MTIME) {
+ rc = cifs_file_flush(xid, inode, cfile);
+ if (rc)
goto cifs_setattr_exit;
- else
- rc = 0;
}
if (attrs->ia_valid & ATTR_SIZE) {
- rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
+ rc = cifs_file_set_size(xid, direntry, full_path,
+ cfile, attrs->ia_size);
if (rc != 0)
goto cifs_setattr_exit;
+ /*
+ * Avoid setting timestamps on the server for ftruncate(2) to
+ * prevent it from disabling automatic timestamp updates as per
+ * MS-FSA 2.1.4.17.
+ */
+ attrs->ia_valid &= ~(ATTR_CTIME | ATTR_MTIME);
}
if (attrs->ia_valid & ATTR_UID)
@@ -3243,8 +3346,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_GID)
gid = attrs->ia_gid;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
+ if (sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) {
if (uid_valid(uid) || gid_valid(gid)) {
mode = NO_CHANGE_64;
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
@@ -3255,9 +3357,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
goto cifs_setattr_exit;
}
}
- } else
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
+ } else if (!(sbflags & CIFS_MOUNT_SET_UID)) {
attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
+ }
/* skip mode change if it's just for clearing setuid/setgid */
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
@@ -3266,9 +3368,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_MODE) {
mode = attrs->ia_mode;
rc = 0;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
- posix) {
+ if ((sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) ||
+ cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
INVALID_UID, INVALID_GID);
if (rc) {
@@ -3290,7 +3391,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
/* fix up mode if we're not using dynperm */
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
+ if ((sbflags & CIFS_MOUNT_DYNPERM) == 0)
attrs->ia_mode = inode->i_mode & ~S_IWUGO;
} else if ((mode & S_IWUGO) &&
(cifsInode->cifsAttrs & ATTR_READONLY)) {
@@ -3301,7 +3402,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
dosattr |= ATTR_NORMAL;
/* reset local inode permissions to normal */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
+ if (!(sbflags & CIFS_MOUNT_DYNPERM)) {
attrs->ia_mode &= ~(S_IALLUGO);
if (S_ISDIR(inode->i_mode))
attrs->ia_mode |=
@@ -3310,7 +3411,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
attrs->ia_mode |=
cifs_sb->ctx->file_mode;
}
- } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
+ } else if (!(sbflags & CIFS_MOUNT_DYNPERM)) {
/* ignore mode change - ATTR_READONLY hasn't changed */
attrs->ia_valid &= ~ATTR_MODE;
}
@@ -3363,7 +3464,14 @@ cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
+ /*
+ * Avoid setting [cm]time with O_TRUNC to prevent the server from
+ * disabling automatic timestamp updates as specified in
+ * MS-FSA 2.1.4.17.
+ */
+ if (attrs->ia_valid & ATTR_OPEN)
+ return 0;
do {
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 56439da4f119..9afab3237e54 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -13,7 +13,6 @@
#include <linux/mount.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -134,7 +133,7 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
struct smb_mnt_fs_info *fsinf;
- fsinf = kzalloc(sizeof(struct smb_mnt_fs_info), GFP_KERNEL);
+ fsinf = kzalloc_obj(struct smb_mnt_fs_info);
if (fsinf == NULL)
return -ENOMEM;
@@ -217,7 +216,7 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
*/
case CIFS_GOING_FLAGS_LOGFLUSH:
case CIFS_GOING_FLAGS_NOLOGFLUSH:
- sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN;
+ atomic_or(CIFS_MOUNT_SHUTDOWN, &sbi->mnt_cifs_flags);
goto shutdown_good;
default:
rc = -EINVAL;
@@ -506,7 +505,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
le16_to_cpu(tcon->ses->server->cipher_type);
pkey_inf.Suid = tcon->ses->Suid;
memcpy(pkey_inf.auth_key, tcon->ses->auth_key.response,
- 16 /* SMB2_NTLMV2_SESSKEY_SIZE */);
+ SMB2_NTLMV2_SESSKEY_SIZE);
memcpy(pkey_inf.smb3decryptionkey,
tcon->ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
memcpy(pkey_inf.smb3encryptionkey,
@@ -588,6 +587,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
break;
default:
cifs_dbg(FYI, "unsupported ioctl\n");
+ trace_smb3_unsupported_ioctl(xid,
+ pSMBFile ? pSMBFile->fid.persistent_fid : 0,
+ command);
break;
}
cifs_ioc_exit:
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index 769752ad2c5c..dd127917a340 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -5,12 +5,12 @@
* Author(s): Steve French (sfrench@us.ibm.com)
*
*/
+#include <crypto/md5.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/namei.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -19,6 +19,7 @@
#include "smb2proto.h"
#include "cifs_ioctl.h"
#include "fs_context.h"
+#include "reparse.h"
/*
* M-F Symlink Functions - Begin
@@ -36,23 +37,6 @@
#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
static int
-symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
-{
- int rc;
- struct shash_desc *md5 = NULL;
-
- rc = cifs_alloc_hash("md5", &md5);
- if (rc)
- return rc;
-
- rc = crypto_shash_digest(md5, link_str, link_len, md5_hash);
- if (rc)
- cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
- cifs_free_hash(&md5);
- return rc;
-}
-
-static int
parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
char **_link_str)
{
@@ -76,11 +60,7 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
return -EINVAL;
- rc = symlink_hash(link_len, link_str, md5_hash);
- if (rc) {
- cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
- return rc;
- }
+ md5(link_str, link_len, md5_hash);
scnprintf(md5_str2, sizeof(md5_str2),
CIFS_MF_SYMLINK_MD5_FORMAT,
@@ -102,7 +82,6 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
static int
format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
{
- int rc;
unsigned int link_len;
unsigned int ofs;
u8 md5_hash[16];
@@ -115,11 +94,7 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
return -ENAMETOOLONG;
- rc = symlink_hash(link_len, link_str, md5_hash);
- if (rc) {
- cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
- return rc;
- }
+ md5(link_str, link_len, md5_hash);
scnprintf(buf, buf_len,
CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
@@ -184,7 +159,8 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
goto out;
if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_symlink_file_size,
+ bytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
out:
kfree(buf);
return rc;
@@ -448,7 +424,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
/* Make sure we wrote all of the symlink data */
if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_short_symlink_write,
+ *pbytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
@@ -475,7 +452,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
struct cifsInodeInfo *cifsInode;
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -526,6 +503,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
if (d_really_is_positive(old_file)) {
cifsInode = CIFS_I(d_inode(old_file));
if (rc == 0) {
+ clear_bit(CIFS_INO_TMPFILE, &cifsInode->flags);
spin_lock(&d_inode(old_file)->i_lock);
inc_nlink(d_inode(old_file));
spin_unlock(&d_inode(old_file)->i_lock);
@@ -567,18 +545,18 @@ int
cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
struct dentry *direntry, const char *symname)
{
- int rc = -EOPNOTSUPP;
- unsigned int xid;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- struct TCP_Server_Info *server;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct inode *newinode = NULL;
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
const char *full_path;
+ int rc = -EOPNOTSUPP;
+ unsigned int sbflags;
+ unsigned int xid;
void *page;
- struct inode *newinode = NULL;
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
page = alloc_dentry_path();
if (!page)
@@ -593,7 +571,6 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
goto symlink_exit;
}
pTcon = tlink_tcon(tlink);
- server = cifs_pick_channel(pTcon->ses);
full_path = build_path_from_dentry(direntry, page);
if (IS_ERR(full_path)) {
@@ -605,15 +582,9 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
cifs_dbg(FYI, "symname is %s\n", symname);
/* BB what if DFS and this volume is on different share? BB */
+ sbflags = cifs_sb_flags(cifs_sb);
rc = -EOPNOTSUPP;
- switch (get_cifs_symlink_type(cifs_sb)) {
- case CIFS_SYMLINK_TYPE_DEFAULT:
- /* should not happen, get_cifs_symlink_type() resolves the default */
- break;
-
- case CIFS_SYMLINK_TYPE_NONE:
- break;
-
+ switch (cifs_symlink_type(cifs_sb)) {
case CIFS_SYMLINK_TYPE_UNIX:
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (pTcon->unix_ext) {
@@ -626,14 +597,14 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
break;
case CIFS_SYMLINK_TYPE_MFSYMLINKS:
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) {
rc = create_mf_symlink(xid, pTcon, cifs_sb,
full_path, symname);
}
break;
case CIFS_SYMLINK_TYPE_SFU:
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ if (sbflags & CIFS_MOUNT_UNX_EMUL) {
rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
full_path, S_IFLNK,
0, symname);
@@ -643,16 +614,14 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
case CIFS_SYMLINK_TYPE_NATIVE:
case CIFS_SYMLINK_TYPE_NFS:
case CIFS_SYMLINK_TYPE_WSL:
- if (server->ops->create_reparse_symlink &&
- (le32_to_cpu(pTcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS)) {
- rc = server->ops->create_reparse_symlink(xid, inode,
- direntry,
- pTcon,
- full_path,
- symname);
+ if (CIFS_REPARSE_SUPPORT(pTcon)) {
+ rc = create_reparse_symlink(xid, inode, direntry, pTcon,
+ full_path, symname);
goto symlink_exit;
}
break;
+ default:
+ break;
}
if (rc == 0) {
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 7b6ed9b23e71..0c54b9b79a2c 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -10,7 +10,6 @@
#include <linux/ctype.h>
#include <linux/mempool.h>
#include <linux/vmalloc.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -18,6 +17,8 @@
#include "nterr.h"
#include "cifs_unicode.h"
#include "smb2pdu.h"
+#include "smb2proto.h"
+#include "smb1proto.h"
#include "cifsfs.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dns_resolve.h"
@@ -27,6 +28,11 @@
#include "fs_context.h"
#include "cached_dir.h"
+struct tcon_list {
+ struct list_head entry;
+ struct cifs_tcon *tcon;
+};
+
/* The xid serves as a useful identifier for each incoming vfs request,
in a similar way to the mid which is useful to track each sent smb,
and CurrentXid can also provide a running counter (although it
@@ -66,7 +72,7 @@ sesInfoAlloc(void)
{
struct cifs_ses *ret_buf;
- ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
+ ret_buf = kzalloc_obj(struct cifs_ses);
if (ret_buf) {
atomic_inc(&sesInfoAllocCount);
spin_lock_init(&ret_buf->ses_lock);
@@ -117,7 +123,7 @@ tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
struct cifs_tcon *ret_buf;
static atomic_t tcon_debug_id;
- ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
+ ret_buf = kzalloc_obj(*ret_buf);
if (!ret_buf)
return NULL;
@@ -151,6 +157,12 @@ tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
#ifdef CONFIG_CIFS_DFS_UPCALL
INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
#endif
+ INIT_LIST_HEAD(&ret_buf->pending_opens);
+ INIT_DELAYED_WORK(&ret_buf->query_interfaces,
+ smb2_query_server_interfaces);
+#ifdef CONFIG_CIFS_DFS_UPCALL
+ INIT_DELAYED_WORK(&ret_buf->dfs_cache_work, dfs_cache_refresh);
+#endif
return ret_buf;
}
@@ -171,10 +183,10 @@ tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
kfree(tcon);
}
-struct smb_hdr *
+void *
cifs_buf_get(void)
{
- struct smb_hdr *ret_buf = NULL;
+ void *ret_buf = NULL;
/*
* SMB2 header is bigger than CIFS one - no problems to clean some
* more bytes for CIFS.
@@ -213,10 +225,10 @@ cifs_buf_release(void *buf_to_free)
return;
}
-struct smb_hdr *
+void *
cifs_small_buf_get(void)
{
- struct smb_hdr *ret_buf = NULL;
+ void *ret_buf = NULL;
/* We could use negotiated size instead of max_msgsize -
but it may be more efficient to always alloc same size
@@ -224,7 +236,6 @@ cifs_small_buf_get(void)
defaults to this and can not be bigger */
ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
/* No need to clear memory here, cleared in header assemble */
- /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
atomic_inc(&small_buf_alloc_count);
#ifdef CONFIG_CIFS_STATS2
atomic_inc(&total_small_buf_alloc_count);
@@ -256,283 +267,6 @@ free_rsp_buf(int resp_buftype, void *rsp)
cifs_buf_release(rsp);
}
-/* NB: MID can not be set if treeCon not passed in, in that
- case it is responsibility of caller to set the mid */
-void
-header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
- const struct cifs_tcon *treeCon, int word_count
- /* length of fixed section (word count) in two byte units */)
-{
- char *temp = (char *) buffer;
-
- memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
-
- buffer->smb_buf_length = cpu_to_be32(
- (2 * word_count) + sizeof(struct smb_hdr) -
- 4 /* RFC 1001 length field does not count */ +
- 2 /* for bcc field itself */) ;
-
- buffer->Protocol[0] = 0xFF;
- buffer->Protocol[1] = 'S';
- buffer->Protocol[2] = 'M';
- buffer->Protocol[3] = 'B';
- buffer->Command = smb_command;
- buffer->Flags = 0x00; /* case sensitive */
- buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
- buffer->Pid = cpu_to_le16((__u16)current->tgid);
- buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
- if (treeCon) {
- buffer->Tid = treeCon->tid;
- if (treeCon->ses) {
- if (treeCon->ses->capabilities & CAP_UNICODE)
- buffer->Flags2 |= SMBFLG2_UNICODE;
- if (treeCon->ses->capabilities & CAP_STATUS32)
- buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-
- /* Uid is not converted */
- buffer->Uid = treeCon->ses->Suid;
- if (treeCon->ses->server)
- buffer->Mid = get_next_mid(treeCon->ses->server);
- }
- if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
- buffer->Flags2 |= SMBFLG2_DFS;
- if (treeCon->nocase)
- buffer->Flags |= SMBFLG_CASELESS;
- if ((treeCon->ses) && (treeCon->ses->server))
- if (treeCon->ses->server->sign)
- buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- }
-
-/* endian conversion of flags is now done just before sending */
- buffer->WordCount = (char) word_count;
- return;
-}
-
-static int
-check_smb_hdr(struct smb_hdr *smb)
-{
- /* does it have the right SMB "signature" ? */
- if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
- cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n",
- *(unsigned int *)smb->Protocol);
- return 1;
- }
-
- /* if it's a response then accept */
- if (smb->Flags & SMBFLG_RESPONSE)
- return 0;
-
- /* only one valid case where server sends us request */
- if (smb->Command == SMB_COM_LOCKING_ANDX)
- return 0;
-
- cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
- get_mid(smb));
- return 1;
-}
-
-int
-checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
-{
- struct smb_hdr *smb = (struct smb_hdr *)buf;
- __u32 rfclen = be32_to_cpu(smb->smb_buf_length);
- __u32 clc_len; /* calculated length */
- cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
- total_read, rfclen);
-
- /* is this frame too small to even get to a BCC? */
- if (total_read < 2 + sizeof(struct smb_hdr)) {
- if ((total_read >= sizeof(struct smb_hdr) - 1)
- && (smb->Status.CifsError != 0)) {
- /* it's an error return */
- smb->WordCount = 0;
- /* some error cases do not return wct and bcc */
- return 0;
- } else if ((total_read == sizeof(struct smb_hdr) + 1) &&
- (smb->WordCount == 0)) {
- char *tmp = (char *)smb;
- /* Need to work around a bug in two servers here */
- /* First, check if the part of bcc they sent was zero */
- if (tmp[sizeof(struct smb_hdr)] == 0) {
- /* some servers return only half of bcc
- * on simple responses (wct, bcc both zero)
- * in particular have seen this on
- * ulogoffX and FindClose. This leaves
- * one byte of bcc potentially uninitialized
- */
- /* zero rest of bcc */
- tmp[sizeof(struct smb_hdr)+1] = 0;
- return 0;
- }
- cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
- } else {
- cifs_dbg(VFS, "Length less than smb header size\n");
- }
- return -EIO;
- } else if (total_read < sizeof(*smb) + 2 * smb->WordCount) {
- cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
- __func__, smb->WordCount);
- return -EIO;
- }
-
- /* otherwise, there is enough to get to the BCC */
- if (check_smb_hdr(smb))
- return -EIO;
- clc_len = smbCalcSize(smb);
-
- if (4 + rfclen != total_read) {
- cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
- rfclen);
- return -EIO;
- }
-
- if (4 + rfclen != clc_len) {
- __u16 mid = get_mid(smb);
- /* check if bcc wrapped around for large read responses */
- if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
- /* check if lengths match mod 64K */
- if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
- return 0; /* bcc wrapped */
- }
- cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
- clc_len, 4 + rfclen, mid);
-
- if (4 + rfclen < clc_len) {
- cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
- rfclen, mid);
- return -EIO;
- } else if (rfclen > clc_len + 512) {
- /*
- * Some servers (Windows XP in particular) send more
- * data than the lengths in the SMB packet would
- * indicate on certain calls (byte range locks and
- * trans2 find first calls in particular). While the
- * client can handle such a frame by ignoring the
- * trailing data, we choose limit the amount of extra
- * data to 512 bytes.
- */
- cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
- rfclen, mid);
- return -EIO;
- }
- }
- return 0;
-}
-
-bool
-is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
-{
- struct smb_hdr *buf = (struct smb_hdr *)buffer;
- struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
- struct TCP_Server_Info *pserver;
- struct cifs_ses *ses;
- struct cifs_tcon *tcon;
- struct cifsInodeInfo *pCifsInode;
- struct cifsFileInfo *netfile;
-
- cifs_dbg(FYI, "Checking for oplock break or dnotify response\n");
- if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
- (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
- struct smb_com_transaction_change_notify_rsp *pSMBr =
- (struct smb_com_transaction_change_notify_rsp *)buf;
- struct file_notify_information *pnotify;
- __u32 data_offset = 0;
- size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
-
- if (get_bcc(buf) > sizeof(struct file_notify_information)) {
- data_offset = le32_to_cpu(pSMBr->DataOffset);
-
- if (data_offset >
- len - sizeof(struct file_notify_information)) {
- cifs_dbg(FYI, "Invalid data_offset %u\n",
- data_offset);
- return true;
- }
- pnotify = (struct file_notify_information *)
- ((char *)&pSMBr->hdr.Protocol + data_offset);
- cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
- pnotify->FileName, pnotify->Action);
- /* cifs_dump_mem("Rcvd notify Data: ",buf,
- sizeof(struct smb_hdr)+60); */
- return true;
- }
- if (pSMBr->hdr.Status.CifsError) {
- cifs_dbg(FYI, "notify err 0x%x\n",
- pSMBr->hdr.Status.CifsError);
- return true;
- }
- return false;
- }
- if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
- return false;
- if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
- /* no sense logging error on invalid handle on oplock
- break - harmless race between close request and oplock
- break response is expected from time to time writing out
- large dirty files cached on the client */
- if ((NT_STATUS_INVALID_HANDLE) ==
- le32_to_cpu(pSMB->hdr.Status.CifsError)) {
- cifs_dbg(FYI, "Invalid handle on oplock break\n");
- return true;
- } else if (ERRbadfid ==
- le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
- return true;
- } else {
- return false; /* on valid oplock brk we get "request" */
- }
- }
- if (pSMB->hdr.WordCount != 8)
- return false;
-
- cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
- pSMB->LockType, pSMB->OplockLevel);
- if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
- return false;
-
- /* If server is a channel, select the primary channel */
- pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
-
- /* look up tcon based on tid & uid */
- spin_lock(&cifs_tcp_ses_lock);
- list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
- if (cifs_ses_exiting(ses))
- continue;
- list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
- if (tcon->tid != buf->Tid)
- continue;
-
- cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
- spin_lock(&tcon->open_file_lock);
- list_for_each_entry(netfile, &tcon->openFileList, tlist) {
- if (pSMB->Fid != netfile->fid.netfid)
- continue;
-
- cifs_dbg(FYI, "file id match, oplock break\n");
- pCifsInode = CIFS_I(d_inode(netfile->dentry));
-
- set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
- &pCifsInode->flags);
-
- netfile->oplock_epoch = 0;
- netfile->oplock_level = pSMB->OplockLevel;
- netfile->oplock_break_cancelled = false;
- cifs_queue_oplock_break(netfile);
-
- spin_unlock(&tcon->open_file_lock);
- spin_unlock(&cifs_tcp_ses_lock);
- return true;
- }
- spin_unlock(&tcon->open_file_lock);
- spin_unlock(&cifs_tcp_ses_lock);
- cifs_dbg(FYI, "No matching file for oplock break\n");
- return true;
- }
- }
- spin_unlock(&cifs_tcp_ses_lock);
- cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
- return true;
-}
-
void
dump_smb(void *buf, int smb_buf_length)
{
@@ -546,13 +280,15 @@ dump_smb(void *buf, int smb_buf_length)
void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_SERVER_INUM) {
struct cifs_tcon *tcon = NULL;
if (cifs_sb->master_tlink)
tcon = cifs_sb_master_tcon(cifs_sb);
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+ atomic_andnot(CIFS_MOUNT_SERVER_INUM, &cifs_sb->mnt_cifs_flags);
cifs_sb->mnt_cifs_serverino_autodisabled = true;
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
tcon ? tcon->tree_name : "new server");
@@ -653,11 +389,13 @@ void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPUID) {
if (uid_eq(cifs_sb->ctx->backupuid, current_fsuid()))
return true;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPGID) {
if (in_group_p(cifs_sb->ctx->backupgid))
return true;
}
@@ -770,7 +508,8 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
cifs_del_deferred_close(cfile);
spin_unlock(&cifs_inode->deferred_lock);
- tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
+ tmp_list = kmalloc_obj(struct file_list,
+ GFP_ATOMIC);
if (tmp_list == NULL)
break;
tmp_list->cfile = cfile;
@@ -802,7 +541,8 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
- tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
+ tmp_list = kmalloc_obj(struct file_list,
+ GFP_ATOMIC);
if (tmp_list == NULL)
break;
tmp_list->cfile = cfile;
@@ -818,33 +558,65 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
kfree(tmp_list);
}
}
-void
-cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
+
+void cifs_close_all_deferred_files_sb(struct cifs_sb_info *cifs_sb)
+{
+ struct rb_root *root = &cifs_sb->tlink_tree;
+ struct rb_node *node;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
+ struct tcon_list *tmp_list, *q;
+ LIST_HEAD(tcon_head);
+
+ spin_lock(&cifs_sb->tlink_tree_lock);
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+ tcon = tlink_tcon(tlink);
+ if (IS_ERR(tcon))
+ continue;
+ tmp_list = kmalloc_obj(struct tcon_list, GFP_ATOMIC);
+ if (tmp_list == NULL)
+ break;
+ tmp_list->tcon = tcon;
+ /* Take a reference on tcon to prevent it from being freed */
+ spin_lock(&tcon->tc_lock);
+ ++tcon->tc_count;
+ trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
+ netfs_trace_tcon_ref_get_close_defer_files);
+ spin_unlock(&tcon->tc_lock);
+ list_add_tail(&tmp_list->entry, &tcon_head);
+ }
+ spin_unlock(&cifs_sb->tlink_tree_lock);
+
+ list_for_each_entry_safe(tmp_list, q, &tcon_head, entry) {
+ cifs_close_all_deferred_files(tmp_list->tcon);
+ list_del(&tmp_list->entry);
+ cifs_put_tcon(tmp_list->tcon, netfs_trace_tcon_ref_put_close_defer_files);
+ kfree(tmp_list);
+ }
+}
+
+void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
+ struct dentry *dentry)
{
- struct cifsFileInfo *cfile;
struct file_list *tmp_list, *tmp_next_list;
- void *page;
- const char *full_path;
+ struct cifsFileInfo *cfile;
LIST_HEAD(file_head);
- page = alloc_dentry_path();
spin_lock(&tcon->open_file_lock);
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
- full_path = build_path_from_dentry(cfile->dentry, page);
- if (strstr(full_path, path)) {
- if (delayed_work_pending(&cfile->deferred)) {
- if (cancel_delayed_work(&cfile->deferred)) {
- spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
- cifs_del_deferred_close(cfile);
- spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
-
- tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
- if (tmp_list == NULL)
- break;
- tmp_list->cfile = cfile;
- list_add_tail(&tmp_list->list, &file_head);
- }
- }
+ if ((cfile->dentry == dentry) &&
+ delayed_work_pending(&cfile->deferred) &&
+ cancel_delayed_work(&cfile->deferred)) {
+ spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+ cifs_del_deferred_close(cfile);
+ spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+
+ tmp_list = kmalloc_obj(struct file_list, GFP_ATOMIC);
+ if (tmp_list == NULL)
+ break;
+ tmp_list->cfile = cfile;
+ list_add_tail(&tmp_list->list, &file_head);
}
}
spin_unlock(&tcon->open_file_lock);
@@ -854,7 +626,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
list_del(&tmp_list->list);
kfree(tmp_list);
}
- free_dentry_path(page);
}
/*
@@ -908,6 +679,14 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
char *data_end;
struct dfs_referral_level_3 *ref;
+ if (rsp_size < sizeof(*rsp)) {
+ cifs_dbg(VFS | ONCE,
+ "%s: header is malformed (size is %u, must be %zu)\n",
+ __func__, rsp_size, sizeof(*rsp));
+ rc = -EINVAL;
+ goto parse_DFS_referrals_exit;
+ }
+
*num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
if (*num_of_nodes < 1) {
@@ -917,6 +696,15 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
goto parse_DFS_referrals_exit;
}
+ if (sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3) > rsp_size) {
+ cifs_dbg(VFS | ONCE,
+ "%s: malformed buffer (size is %u, must be at least %zu)\n",
+ __func__, rsp_size,
+ sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3));
+ rc = -EINVAL;
+ goto parse_DFS_referrals_exit;
+ }
+
ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
if (ref->VersionNumber != cpu_to_le16(3)) {
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
@@ -931,8 +719,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
*num_of_nodes, le32_to_cpu(rsp->DFSFlags));
- *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
- GFP_KERNEL);
+ *target_nodes = kzalloc_objs(struct dfs_info3_param, *num_of_nodes);
if (*target_nodes == NULL) {
rc = -ENOMEM;
goto parse_DFS_referrals_exit;
@@ -998,63 +785,6 @@ parse_DFS_referrals_exit:
return rc;
}
-/**
- * cifs_alloc_hash - allocate hash and hash context together
- * @name: The name of the crypto hash algo
- * @sdesc: SHASH descriptor where to put the pointer to the hash TFM
- *
- * The caller has to make sure @sdesc is initialized to either NULL or
- * a valid context. It can be freed via cifs_free_hash().
- */
-int
-cifs_alloc_hash(const char *name, struct shash_desc **sdesc)
-{
- int rc = 0;
- struct crypto_shash *alg = NULL;
-
- if (*sdesc)
- return 0;
-
- alg = crypto_alloc_shash(name, 0, 0);
- if (IS_ERR(alg)) {
- cifs_dbg(VFS, "Could not allocate shash TFM '%s'\n", name);
- rc = PTR_ERR(alg);
- *sdesc = NULL;
- return rc;
- }
-
- *sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL);
- if (*sdesc == NULL) {
- cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name);
- crypto_free_shash(alg);
- return -ENOMEM;
- }
-
- (*sdesc)->tfm = alg;
- return 0;
-}
-
-/**
- * cifs_free_hash - free hash and hash context together
- * @sdesc: Where to find the pointer to the hash TFM
- *
- * Freeing a NULL descriptor is safe.
- */
-void
-cifs_free_hash(struct shash_desc **sdesc)
-{
- if (unlikely(!sdesc) || !*sdesc)
- return;
-
- if ((*sdesc)->tfm) {
- crypto_free_shash((*sdesc)->tfm);
- (*sdesc)->tfm = NULL;
- }
-
- kfree_sensitive(*sdesc);
- *sdesc = NULL;
-}
-
void extract_unc_hostname(const char *unc, const char **h, size_t *len)
{
const char *end;
@@ -1214,7 +944,7 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
}
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
return 0;
}
@@ -1243,7 +973,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
* look up or tcon is not DFS.
*/
if (strlen(full_path) < 2 || !cifs_sb ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
+ (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_DFS) ||
!is_tcon_dfs(tcon))
return 0;
diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c
index e3f9213131c4..52a520349cb7 100644
--- a/fs/smb/client/namespace.c
+++ b/fs/smb/client/namespace.c
@@ -146,6 +146,9 @@ static char *automount_fullpath(struct dentry *dentry, void *page)
}
spin_unlock(&tcon->tc_lock);
+ if (unlikely(!page))
+ return ERR_PTR(-ENOMEM);
+
s = dentry_path_raw(dentry, page, PATH_MAX);
if (IS_ERR(s))
return s;
@@ -283,7 +286,6 @@ struct vfsmount *cifs_d_automount(struct path *path)
return newmnt;
}
- mntget(newmnt); /* prevent immediate expiration */
mnt_set_expiry(newmnt, &cifs_automount_list);
schedule_delayed_work(&cifs_automount_task,
cifs_mountpoint_expiry_timeout);
diff --git a/fs/smb/client/netlink.h b/fs/smb/client/netlink.h
index e2fa8ed24c54..d35eef981b6b 100644
--- a/fs/smb/client/netlink.h
+++ b/fs/smb/client/netlink.h
@@ -10,7 +10,7 @@
extern struct genl_family cifs_genl_family;
-extern int cifs_genl_init(void);
-extern void cifs_genl_exit(void);
+int cifs_genl_init(void);
+void cifs_genl_exit(void);
#endif /* _CIFS_NETLINK_H */
diff --git a/fs/smb/client/netmisc.c b/fs/smb/client/netmisc.c
index 9ec20601cee2..bddadee82d0c 100644
--- a/fs/smb/client/netmisc.c
+++ b/fs/smb/client/netmisc.c
@@ -17,105 +17,13 @@
#include <asm/byteorder.h>
#include <linux/inet.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
+#include "smb1proto.h"
#include "smberr.h"
#include "cifs_debug.h"
#include "nterr.h"
-struct smb_to_posix_error {
- __u16 smb_err;
- int posix_code;
-};
-
-static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
- {ERRbadfunc, -EINVAL},
- {ERRbadfile, -ENOENT},
- {ERRbadpath, -ENOTDIR},
- {ERRnofids, -EMFILE},
- {ERRnoaccess, -EACCES},
- {ERRbadfid, -EBADF},
- {ERRbadmcb, -EIO},
- {ERRnomem, -EREMOTEIO},
- {ERRbadmem, -EFAULT},
- {ERRbadenv, -EFAULT},
- {ERRbadformat, -EINVAL},
- {ERRbadaccess, -EACCES},
- {ERRbaddata, -EIO},
- {ERRbaddrive, -ENXIO},
- {ERRremcd, -EACCES},
- {ERRdiffdevice, -EXDEV},
- {ERRnofiles, -ENOENT},
- {ERRwriteprot, -EROFS},
- {ERRbadshare, -EBUSY},
- {ERRlock, -EACCES},
- {ERRunsup, -EINVAL},
- {ERRnosuchshare, -ENXIO},
- {ERRfilexists, -EEXIST},
- {ERRinvparm, -EINVAL},
- {ERRdiskfull, -ENOSPC},
- {ERRinvname, -ENOENT},
- {ERRinvlevel, -EOPNOTSUPP},
- {ERRdirnotempty, -ENOTEMPTY},
- {ERRnotlocked, -ENOLCK},
- {ERRcancelviolation, -ENOLCK},
- {ERRalreadyexists, -EEXIST},
- {ERRmoredata, -EOVERFLOW},
- {ERReasnotsupported, -EOPNOTSUPP},
- {ErrQuota, -EDQUOT},
- {ErrNotALink, -ENOLINK},
- {ERRnetlogonNotStarted, -ENOPROTOOPT},
- {ERRsymlink, -EOPNOTSUPP},
- {ErrTooManyLinks, -EMLINK},
- {0, 0}
-};
-
-static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
- {ERRerror, -EIO},
- {ERRbadpw, -EACCES}, /* was EPERM */
- {ERRbadtype, -EREMOTE},
- {ERRaccess, -EACCES},
- {ERRinvtid, -ENXIO},
- {ERRinvnetname, -ENXIO},
- {ERRinvdevice, -ENXIO},
- {ERRqfull, -ENOSPC},
- {ERRqtoobig, -ENOSPC},
- {ERRqeof, -EIO},
- {ERRinvpfid, -EBADF},
- {ERRsmbcmd, -EBADRQC},
- {ERRsrverror, -EIO},
- {ERRbadBID, -EIO},
- {ERRfilespecs, -EINVAL},
- {ERRbadLink, -EIO},
- {ERRbadpermits, -EINVAL},
- {ERRbadPID, -ESRCH},
- {ERRsetattrmode, -EINVAL},
- {ERRpaused, -EHOSTDOWN},
- {ERRmsgoff, -EHOSTDOWN},
- {ERRnoroom, -ENOSPC},
- {ERRrmuns, -EUSERS},
- {ERRtimeout, -ETIME},
- {ERRnoresource, -EREMOTEIO},
- {ERRtoomanyuids, -EUSERS},
- {ERRbaduid, -EACCES},
- {ERRusempx, -EIO},
- {ERRusestd, -EIO},
- {ERR_NOTIFY_ENUM_DIR, -ENOBUFS},
- {ERRnoSuchUser, -EACCES},
-/* {ERRaccountexpired, -EACCES},
- {ERRbadclient, -EACCES},
- {ERRbadLogonTime, -EACCES},
- {ERRpasswordExpired, -EACCES},*/
- {ERRaccountexpired, -EKEYEXPIRED},
- {ERRbadclient, -EACCES},
- {ERRbadLogonTime, -EACCES},
- {ERRpasswordExpired, -EKEYEXPIRED},
-
- {ERRnosupport, -EINVAL},
- {0, 0}
-};
-
/*
* Convert a string containing text IPv4 or IPv6 address to binary form.
*
@@ -199,731 +107,6 @@ cifs_set_port(struct sockaddr *addr, const unsigned short int port)
}
}
-/*****************************************************************************
-convert a NT status code to a dos class/code
- *****************************************************************************/
-/* NT status -> dos error map */
-static const struct {
- __u8 dos_class;
- __u16 dos_code;
- __u32 ntstatus;
-} ntstatus_to_dos_map[] = {
- {
- ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
- ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
- ERRDOS, ERRinvlevel, NT_STATUS_INVALID_INFO_CLASS}, {
- ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
- ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
- ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, {
- ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, {
- ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, {
- ERRDOS, 87, NT_STATUS_INVALID_CID}, {
- ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, {
- ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, {
- ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, {
- ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, {
- ERRDOS, 38, NT_STATUS_END_OF_FILE}, {
- ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, {
- ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
- ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
- during the session setup } */
- {
- ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
- ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, {
- ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, {
- ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, {
- ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, {
- ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, {
- ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, {
- ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, {
- ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, {
- ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
- ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
- during the session setup } */
- {
- ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
- ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, {
- ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, {
- ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, {
- ERRDOS, 158, NT_STATUS_NOT_LOCKED}, {
- ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, {
- ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, {
- ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, {
- ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, {
- ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
- /* mapping changed since shell does lookup on * expects FileNotFound */
- ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, {
- ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
- ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, {
- ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
- ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
- ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, {
- ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, {
- ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, {
- ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, {
- ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, {
- ERRDOS, 23, NT_STATUS_DATA_ERROR}, {
- ERRDOS, 23, NT_STATUS_CRC_ERROR}, {
- ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, {
- ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, {
- ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, {
- ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, {
- ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, {
- ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, {
- ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, {
- ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, {
- ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, {
- ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, {
- ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, {
- ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, {
- ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
- ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
- ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
- ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED}, {
- ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
- ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
- ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
- ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, {
- ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
- ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, {
- ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
- ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
- during the session setup } */
- {
- ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */
- ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, {
- ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, {
- ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
- ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
- during the session setup } */
- {
- ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
- ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, {
- ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, {
- ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
- ERRSRV, ERRbadLogonTime, NT_STATUS_INVALID_LOGON_HOURS}, {
- ERRSRV, ERRbadclient, NT_STATUS_INVALID_WORKSTATION}, {
- ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, {
- ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_DISABLED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, {
- ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, {
- ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, {
- ERRDOS, 112, NT_STATUS_DISK_FULL}, {
- ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, {
- ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, {
- ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, {
- ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, {
- ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, {
- ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, {
- ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, {
- ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, {
- ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, {
- ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, {
- ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, {
- ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
- ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_INSUFFICIENT_RESOURCES to
- NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
- {
- ERRDOS, ERRnoresource, NT_STATUS_INSUFFICIENT_RESOURCES}, {
- ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
- ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, {
- ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, {
- ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, {
- ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, {
- ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, {
- ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, {
- ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, {
- ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, {
- ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, {
- ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, {
- ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, {
- ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, {
- ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, {
- ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, {
- ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, {
- ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, {
- ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, {
- ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, {
- ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, {
- ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, {
- ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, {
- ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, {
- ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, {
- ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, {
- ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, {
- ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, {
- ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, {
- ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, {
- ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, {
- ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, {
- ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, {
- ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, {
- ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, {
- ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, {
- ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, {
- ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, {
- ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, {
- ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, {
- ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, {
- ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, {
- ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, {
- ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, {
- ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, {
- ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, {
- ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, {
- ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, {
- ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, {
- ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, {
- ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, {
- ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, {
- ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, {
- ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, {
- ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, {
- ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, {
- ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, {
- ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, {
- ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, {
- ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, {
- ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, {
- ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, {
- ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, {
- ERRDOS, 203, 0xc0000100}, {
- ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, {
- ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, {
- ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, {
- ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, {
- ERRDOS, 2401, NT_STATUS_FILES_OPEN}, {
- ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, {
- ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, {
- ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, {
- ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, {
- ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, {
- ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, {
- ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, {
- ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, {
- ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, {
- ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, {
- ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, {
- ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, {
- ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, {
- ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, {
- ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, {
- ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, {
- ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, {
- ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, {
- ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, {
- ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, {
- ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, {
- ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, {
- ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, {
- ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, {
- ERRDOS, 59, NT_STATUS_LINK_FAILED}, {
- ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, {
- ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, {
- ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, {
- ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, {
- ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, {
- ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, {
- ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, {
- ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, {
- ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, {
- ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, {
- ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, {
- ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, {
- ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, {
- ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, {
- ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, {
- ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, {
- ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, {
- ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, {
- ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, {
- ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, {
- ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, {
- ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, {
- ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, {
- ERRHRD, ERRgeneral, 0xc000016e}, {
- ERRHRD, ERRgeneral, 0xc000016f}, {
- ERRHRD, ERRgeneral, 0xc0000170}, {
- ERRHRD, ERRgeneral, 0xc0000171}, {
- ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, {
- ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, {
- ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, {
- ERRHRD, ERRgeneral, 0xc0000179}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, {
- ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, {
- ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, {
- ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, {
- ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, {
- ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, {
- ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, {
- ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, {
- ERRDOS, 19, NT_STATUS_TOO_LATE}, {
- ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
- NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
- {
- ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
- ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
- ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, {
- ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, {
- ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, {
- ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, {
- ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_EXPIRED}, {
- ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, {
- ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, {
- ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, {
- ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, {
- ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, {
- ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
- ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
-/* { This NT error code was 'sqashed'
- from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
- during the session setup } */
- {
- ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
- ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, {
- ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, {
- ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, {
- ERRDOS, ERRnoresource, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, {
- ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, {
- ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, {
- ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, {
- ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, {
- ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, {
- ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, {
- ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, {
- ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, {
- ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, {
- ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, {
- ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, {
- ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, {
- ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, {
- ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, {
- ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
- ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
- ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
- ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
- ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, {
- ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, {
- ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, {
- ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, {
- ERRHRD, ERRgeneral, NT_STATUS_RETRY}, {
- ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, {
- ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, {
- ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, {
- ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, {
- ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, {
- ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, {
- ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, {
- ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, {
- ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, {
- ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, {
- ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, {
- ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, {
- ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, {
- ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, {
- ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, {
- ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, {
- ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, {
- ERRHRD, ERRgeneral, 0xc000024a}, {
- ERRHRD, ERRgeneral, 0xc000024b}, {
- ERRHRD, ERRgeneral, 0xc000024c}, {
- ERRHRD, ERRgeneral, 0xc000024d}, {
- ERRHRD, ERRgeneral, 0xc000024e}, {
- ERRHRD, ERRgeneral, 0xc000024f}, {
- ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, {
- ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, {
- ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, {
- ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, {
- ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, {
- ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, {
- ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, {
- ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, {
- ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, {
- ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, {
- ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, {
- ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, {
- ERRHRD, ERRgeneral, 0xc000025d}, {
- ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, {
- ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, {
- ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, {
- ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
- ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
- ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
- ERRDOS, ErrTooManyLinks, NT_STATUS_TOO_MANY_LINKS}, {
- ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
- ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
- ERRDOS, 21, 0xc000026e}, {
- ERRDOS, 161, 0xc0000281}, {
- ERRDOS, ERRnoaccess, 0xc000028a}, {
- ERRDOS, ERRnoaccess, 0xc000028b}, {
- ERRHRD, ERRgeneral, 0xc000028c}, {
- ERRDOS, ERRnoaccess, 0xc000028d}, {
- ERRDOS, ERRnoaccess, 0xc000028e}, {
- ERRDOS, ERRnoaccess, 0xc000028f}, {
- ERRDOS, ERRnoaccess, 0xc0000290}, {
- ERRDOS, ERRbadfunc, 0xc000029c}, {
- ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, {
- ERRDOS, ERRinvlevel, 0x007c0001}, {
- 0, 0, 0 }
-};
-
-/*****************************************************************************
- Print an error message from the status code
- *****************************************************************************/
-static void
-cifs_print_status(__u32 status_code)
-{
- int idx = 0;
-
- while (nt_errs[idx].nt_errstr != NULL) {
- if (nt_errs[idx].nt_errcode == status_code) {
- pr_notice("Status code returned 0x%08x %s\n",
- status_code, nt_errs[idx].nt_errstr);
- return;
- }
- idx++;
- }
- return;
-}
-
-
-static void
-ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
-{
- int i;
- if (ntstatus == 0) {
- *eclass = 0;
- *ecode = 0;
- return;
- }
- for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) {
- if (ntstatus == ntstatus_to_dos_map[i].ntstatus) {
- *eclass = ntstatus_to_dos_map[i].dos_class;
- *ecode = ntstatus_to_dos_map[i].dos_code;
- return;
- }
- }
- *eclass = ERRHRD;
- *ecode = ERRgeneral;
-}
-
-int
-map_smb_to_linux_error(char *buf, bool logErr)
-{
- struct smb_hdr *smb = (struct smb_hdr *)buf;
- unsigned int i;
- int rc = -EIO; /* if transport error smb error may not be set */
- __u8 smberrclass;
- __u16 smberrcode;
-
- /* BB if NT Status codes - map NT BB */
-
- /* old style smb error codes */
- if (smb->Status.CifsError == 0)
- return 0;
-
- if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
- /* translate the newer STATUS codes to old style SMB errors
- * and then to POSIX errors */
- __u32 err = le32_to_cpu(smb->Status.CifsError);
- if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED)))
- cifs_print_status(err);
- else if (cifsFYI & CIFS_RC)
- cifs_print_status(err);
- ntstatus_to_dos(err, &smberrclass, &smberrcode);
- } else {
- smberrclass = smb->Status.DosError.ErrorClass;
- smberrcode = le16_to_cpu(smb->Status.DosError.Error);
- }
-
- /* old style errors */
-
- /* DOS class smb error codes - map DOS */
- if (smberrclass == ERRDOS) {
- /* 1 byte field no need to byte reverse */
- for (i = 0;
- i <
- sizeof(mapping_table_ERRDOS) /
- sizeof(struct smb_to_posix_error); i++) {
- if (mapping_table_ERRDOS[i].smb_err == 0)
- break;
- else if (mapping_table_ERRDOS[i].smb_err ==
- smberrcode) {
- rc = mapping_table_ERRDOS[i].posix_code;
- break;
- }
- /* else try next error mapping one to see if match */
- }
- } else if (smberrclass == ERRSRV) {
- /* server class of error codes */
- for (i = 0;
- i <
- sizeof(mapping_table_ERRSRV) /
- sizeof(struct smb_to_posix_error); i++) {
- if (mapping_table_ERRSRV[i].smb_err == 0)
- break;
- else if (mapping_table_ERRSRV[i].smb_err ==
- smberrcode) {
- rc = mapping_table_ERRSRV[i].posix_code;
- break;
- }
- /* else try next error mapping to see if match */
- }
- }
- /* else ERRHRD class errors or junk - return EIO */
-
- /* special cases for NT status codes which cannot be translated to DOS codes */
- if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
- __u32 err = le32_to_cpu(smb->Status.CifsError);
- if (err == (NT_STATUS_NOT_A_REPARSE_POINT))
- rc = -ENODATA;
- else if (err == (NT_STATUS_PRIVILEGE_NOT_HELD))
- rc = -EPERM;
- }
-
- cifs_dbg(FYI, "Mapping smb error code 0x%x to POSIX err %d\n",
- le32_to_cpu(smb->Status.CifsError), rc);
-
- /* generic corrective action e.g. reconnect SMB session on
- * ERRbaduid could be added */
-
- return rc;
-}
-
-int
-map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
-{
- int rc;
- struct smb_hdr *smb = (struct smb_hdr *)mid->resp_buf;
-
- rc = map_smb_to_linux_error((char *)smb, logErr);
- if (rc == -EACCES && !(smb->Flags2 & SMBFLG2_ERR_STATUS)) {
- /* possible ERRBaduid */
- __u8 class = smb->Status.DosError.ErrorClass;
- __u16 code = le16_to_cpu(smb->Status.DosError.Error);
-
- /* switch can be used to handle different errors */
- if (class == ERRSRV && code == ERRbaduid) {
- cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
- code);
- cifs_signal_cifsd_for_reconnect(mid->server, false);
- }
- }
-
- return rc;
-}
-
-
-/*
- * calculate the size of the SMB message based on the fixed header
- * portion, the number of word parameters and the data portion of the message
- */
-unsigned int
-smbCalcSize(void *buf)
-{
- struct smb_hdr *ptr = buf;
- return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
- 2 /* size of the bcc field */ + get_bcc(ptr));
-}
-
/* The following are taken from fs/ntfs/util.c */
#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
diff --git a/fs/smb/client/nterr.c b/fs/smb/client/nterr.c
deleted file mode 100644
index 8f0bc441295e..000000000000
--- a/fs/smb/client/nterr.c
+++ /dev/null
@@ -1,683 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Unix SMB/Netbios implementation.
- * Version 1.9.
- * RPC Pipe client / server routines
- * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
- */
-
-/* NT error codes - see nterr.h */
-#include <linux/types.h>
-#include <linux/fs.h>
-#include "nterr.h"
-
-const struct nt_err_code_struct nt_errs[] = {
- {"NT_STATUS_OK", NT_STATUS_OK},
- {"NT_STATUS_MEDIA_CHANGED", NT_STATUS_MEDIA_CHANGED},
- {"NT_STATUS_END_OF_MEDIA", NT_STATUS_END_OF_MEDIA},
- {"NT_STATUS_MEDIA_CHECK", NT_STATUS_MEDIA_CHECK},
- {"NT_STATUS_NO_DATA_DETECTED", NT_STATUS_NO_DATA_DETECTED},
- {"NT_STATUS_STOPPED_ON_SYMLINK", NT_STATUS_STOPPED_ON_SYMLINK},
- {"NT_STATUS_DEVICE_REQUIRES_CLEANING", NT_STATUS_DEVICE_REQUIRES_CLEANING},
- {"NT_STATUS_DEVICE_DOOR_OPEN", NT_STATUS_DEVICE_DOOR_OPEN},
- {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL},
- {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED},
- {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS},
- {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH},
- {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION},
- {"NT_STATUS_BUFFER_OVERFLOW", NT_STATUS_BUFFER_OVERFLOW},
- {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR},
- {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA},
- {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE},
- {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK},
- {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC},
- {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID},
- {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED},
- {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER},
- {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE},
- {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE},
- {"NT_STATUS_INVALID_DEVICE_REQUEST",
- NT_STATUS_INVALID_DEVICE_REQUEST},
- {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE},
- {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME},
- {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE},
- {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA},
- {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR},
- {"NT_STATUS_MORE_PROCESSING_REQUIRED",
- NT_STATUS_MORE_PROCESSING_REQUIRED},
- {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY},
- {"NT_STATUS_CONFLICTING_ADDRESSES",
- NT_STATUS_CONFLICTING_ADDRESSES},
- {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW},
- {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM},
- {"NT_STATUS_UNABLE_TO_DELETE_SECTION",
- NT_STATUS_UNABLE_TO_DELETE_SECTION},
- {"NT_STATUS_INVALID_SYSTEM_SERVICE",
- NT_STATUS_INVALID_SYSTEM_SERVICE},
- {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION},
- {"NT_STATUS_INVALID_LOCK_SEQUENCE",
- NT_STATUS_INVALID_LOCK_SEQUENCE},
- {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE},
- {"NT_STATUS_INVALID_FILE_FOR_SECTION",
- NT_STATUS_INVALID_FILE_FOR_SECTION},
- {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED},
- {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED},
- {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL},
- {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH},
- {"NT_STATUS_NONCONTINUABLE_EXCEPTION",
- NT_STATUS_NONCONTINUABLE_EXCEPTION},
- {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION},
- {"NT_STATUS_UNWIND", NT_STATUS_UNWIND},
- {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK},
- {"NT_STATUS_INVALID_UNWIND_TARGET",
- NT_STATUS_INVALID_UNWIND_TARGET},
- {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED},
- {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR},
- {"NT_STATUS_UNABLE_TO_DECOMMIT_VM",
- NT_STATUS_UNABLE_TO_DECOMMIT_VM},
- {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED},
- {"NT_STATUS_INVALID_PORT_ATTRIBUTES",
- NT_STATUS_INVALID_PORT_ATTRIBUTES},
- {"NT_STATUS_PORT_MESSAGE_TOO_LONG",
- NT_STATUS_PORT_MESSAGE_TOO_LONG},
- {"NT_STATUS_INVALID_PARAMETER_MIX",
- NT_STATUS_INVALID_PARAMETER_MIX},
- {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER},
- {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR},
- {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID},
- {"NT_STATUS_OBJECT_NAME_NOT_FOUND",
- NT_STATUS_OBJECT_NAME_NOT_FOUND},
- {"NT_STATUS_OBJECT_NAME_COLLISION",
- NT_STATUS_OBJECT_NAME_COLLISION},
- {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE},
- {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED},
- {"NT_STATUS_DEVICE_ALREADY_ATTACHED",
- NT_STATUS_DEVICE_ALREADY_ATTACHED},
- {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID},
- {"NT_STATUS_OBJECT_PATH_NOT_FOUND",
- NT_STATUS_OBJECT_PATH_NOT_FOUND},
- {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD",
- NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
- {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN},
- {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR},
- {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR},
- {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR},
- {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG},
- {"NT_STATUS_PORT_CONNECTION_REFUSED",
- NT_STATUS_PORT_CONNECTION_REFUSED},
- {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE},
- {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION},
- {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED},
- {"NT_STATUS_INVALID_PAGE_PROTECTION",
- NT_STATUS_INVALID_PAGE_PROTECTION},
- {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED},
- {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED",
- NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
- {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET},
- {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE},
- {"NT_STATUS_SUSPEND_COUNT_EXCEEDED",
- NT_STATUS_SUSPEND_COUNT_EXCEEDED},
- {"NT_STATUS_THREAD_IS_TERMINATING",
- NT_STATUS_THREAD_IS_TERMINATING},
- {"NT_STATUS_BAD_WORKING_SET_LIMIT",
- NT_STATUS_BAD_WORKING_SET_LIMIT},
- {"NT_STATUS_INCOMPATIBLE_FILE_MAP",
- NT_STATUS_INCOMPATIBLE_FILE_MAP},
- {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION},
- {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED},
- {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE},
- {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY},
- {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE},
- {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR},
- {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT},
- {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED},
- {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING},
- {"NT_STATUS_CTL_FILE_NOT_SUPPORTED",
- NT_STATUS_CTL_FILE_NOT_SUPPORTED},
- {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION},
- {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH},
- {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER},
- {"NT_STATUS_INVALID_PRIMARY_GROUP",
- NT_STATUS_INVALID_PRIMARY_GROUP},
- {"NT_STATUS_NO_IMPERSONATION_TOKEN",
- NT_STATUS_NO_IMPERSONATION_TOKEN},
- {"NT_STATUS_CANT_DISABLE_MANDATORY",
- NT_STATUS_CANT_DISABLE_MANDATORY},
- {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS},
- {"NT_STATUS_NO_SUCH_LOGON_SESSION",
- NT_STATUS_NO_SUCH_LOGON_SESSION},
- {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE},
- {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD},
- {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME},
- {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS},
- {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER},
- {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS},
- {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP},
- {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP},
- {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP},
- {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN},
- {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD},
- {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD},
- {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION},
- {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE},
- {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION},
- {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS},
- {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION},
- {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED},
- {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED},
- {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED},
- {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED",
- NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
- {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED},
- {"NT_STATUS_INVALID_SUB_AUTHORITY",
- NT_STATUS_INVALID_SUB_AUTHORITY},
- {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL},
- {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID},
- {"NT_STATUS_INVALID_SECURITY_DESCR",
- NT_STATUS_INVALID_SECURITY_DESCR},
- {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND},
- {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT},
- {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN},
- {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL},
- {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED},
- {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL},
- {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED},
- {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED},
- {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED",
- NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
- {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED},
- {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY},
- {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED},
- {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL},
- {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED},
- {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA},
- {"NT_STATUS_RESOURCE_DATA_NOT_FOUND",
- NT_STATUS_RESOURCE_DATA_NOT_FOUND},
- {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND",
- NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
- {"NT_STATUS_RESOURCE_NAME_NOT_FOUND",
- NT_STATUS_RESOURCE_NAME_NOT_FOUND},
- {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED",
- NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
- {"NT_STATUS_FLOAT_DENORMAL_OPERAND",
- NT_STATUS_FLOAT_DENORMAL_OPERAND},
- {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
- {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT},
- {"NT_STATUS_FLOAT_INVALID_OPERATION",
- NT_STATUS_FLOAT_INVALID_OPERATION},
- {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW},
- {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK},
- {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW},
- {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO",
- NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
- {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW},
- {"NT_STATUS_PRIVILEGED_INSTRUCTION",
- NT_STATUS_PRIVILEGED_INSTRUCTION},
- {"NT_STATUS_TOO_MANY_PAGING_FILES",
- NT_STATUS_TOO_MANY_PAGING_FILES},
- {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID},
- {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED",
- NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
- {"NT_STATUS_INSUFFICIENT_RESOURCES",
- NT_STATUS_INSUFFICIENT_RESOURCES},
- {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND},
- {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR},
- {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED},
- {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE},
- {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE},
- {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED},
- {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA},
- {"NT_STATUS_MEDIA_WRITE_PROTECTED",
- NT_STATUS_MEDIA_WRITE_PROTECTED},
- {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY},
- {"NT_STATUS_INVALID_GROUP_ATTRIBUTES",
- NT_STATUS_INVALID_GROUP_ATTRIBUTES},
- {"NT_STATUS_BAD_IMPERSONATION_LEVEL",
- NT_STATUS_BAD_IMPERSONATION_LEVEL},
- {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS},
- {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS},
- {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE},
- {"NT_STATUS_BAD_MASTER_BOOT_RECORD",
- NT_STATUS_BAD_MASTER_BOOT_RECORD},
- {"NT_STATUS_INSTRUCTION_MISALIGNMENT",
- NT_STATUS_INSTRUCTION_MISALIGNMENT},
- {"NT_STATUS_INSTANCE_NOT_AVAILABLE",
- NT_STATUS_INSTANCE_NOT_AVAILABLE},
- {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE},
- {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE},
- {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY},
- {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION},
- {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED},
- {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING},
- {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED},
- {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING},
- {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE},
- {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT},
- {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED},
- {"NT_STATUS_PROFILING_NOT_STARTED",
- NT_STATUS_PROFILING_NOT_STARTED},
- {"NT_STATUS_PROFILING_NOT_STOPPED",
- NT_STATUS_PROFILING_NOT_STOPPED},
- {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET},
- {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY},
- {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED},
- {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING},
- {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME},
- {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH},
- {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY},
- {"NT_STATUS_DEVICE_DOES_NOT_EXIST",
- NT_STATUS_DEVICE_DOES_NOT_EXIST},
- {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS},
- {"NT_STATUS_ADAPTER_HARDWARE_ERROR",
- NT_STATUS_ADAPTER_HARDWARE_ERROR},
- {"NT_STATUS_INVALID_NETWORK_RESPONSE",
- NT_STATUS_INVALID_NETWORK_RESPONSE},
- {"NT_STATUS_UNEXPECTED_NETWORK_ERROR",
- NT_STATUS_UNEXPECTED_NETWORK_ERROR},
- {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER},
- {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL},
- {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE},
- {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED},
- {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED},
- {"NT_STATUS_NETWORK_ACCESS_DENIED",
- NT_STATUS_NETWORK_ACCESS_DENIED},
- {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE},
- {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME},
- {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES},
- {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS},
- {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED},
- {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED},
- {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED},
- {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT},
- {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT},
- {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE},
- {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED},
- {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED",
- NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
- {"NT_STATUS_NO_SECURITY_ON_OBJECT",
- NT_STATUS_NO_SECURITY_ON_OBJECT},
- {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT},
- {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY},
- {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO",
- NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
- {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF},
- {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE},
- {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE},
- {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE},
- {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN},
- {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS},
- {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED",
- NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
- {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED},
- {"NT_STATUS_INVALID_OPLOCK_PROTOCOL",
- NT_STATUS_INVALID_OPLOCK_PROTOCOL},
- {"NT_STATUS_INTERNAL_DB_CORRUPTION",
- NT_STATUS_INTERNAL_DB_CORRUPTION},
- {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR},
- {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED},
- {"NT_STATUS_BAD_DESCRIPTOR_FORMAT",
- NT_STATUS_BAD_DESCRIPTOR_FORMAT},
- {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER},
- {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR},
- {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR",
- NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
- {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR",
- NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
- {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR",
- NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
- {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS},
- {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS},
- {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1},
- {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2},
- {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3},
- {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4},
- {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5},
- {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6},
- {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7},
- {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8},
- {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9},
- {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10},
- {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11},
- {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12},
- {"NT_STATUS_REDIRECTOR_NOT_STARTED",
- NT_STATUS_REDIRECTOR_NOT_STARTED},
- {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED},
- {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW},
- {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE},
- {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE},
- {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY},
- {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR},
- {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY},
- {"NT_STATUS_BAD_LOGON_SESSION_STATE",
- NT_STATUS_BAD_LOGON_SESSION_STATE},
- {"NT_STATUS_LOGON_SESSION_COLLISION",
- NT_STATUS_LOGON_SESSION_COLLISION},
- {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG},
- {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN},
- {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE},
- {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND},
- {"NT_STATUS_PROCESS_IS_TERMINATING",
- NT_STATUS_PROCESS_IS_TERMINATING},
- {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE},
- {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION},
- {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE},
- {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED},
- {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT},
- {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST},
- {"NT_STATUS_ABIOS_LID_ALREADY_OWNED",
- NT_STATUS_ABIOS_LID_ALREADY_OWNED},
- {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER},
- {"NT_STATUS_ABIOS_INVALID_COMMAND",
- NT_STATUS_ABIOS_INVALID_COMMAND},
- {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID},
- {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE",
- NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
- {"NT_STATUS_ABIOS_INVALID_SELECTOR",
- NT_STATUS_ABIOS_INVALID_SELECTOR},
- {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT},
- {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE},
- {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET},
- {"NT_STATUS_INVALID_LDT_DESCRIPTOR",
- NT_STATUS_INVALID_LDT_DESCRIPTOR},
- {"NT_STATUS_INVALID_IMAGE_NE_FORMAT",
- NT_STATUS_INVALID_IMAGE_NE_FORMAT},
- {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE},
- {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE},
- {"NT_STATUS_MAPPED_FILE_SIZE_ZERO",
- NT_STATUS_MAPPED_FILE_SIZE_ZERO},
- {"NT_STATUS_TOO_MANY_OPENED_FILES",
- NT_STATUS_TOO_MANY_OPENED_FILES},
- {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED},
- {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE},
- {"NT_STATUS_INVALID_COMPUTER_NAME",
- NT_STATUS_INVALID_COMPUTER_NAME},
- {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED},
- {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT},
- {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP},
- {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER},
- {"NT_STATUS_MEMBERS_PRIMARY_GROUP",
- NT_STATUS_MEMBERS_PRIMARY_GROUP},
- {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED},
- {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS},
- {"NT_STATUS_THREAD_NOT_IN_PROCESS",
- NT_STATUS_THREAD_NOT_IN_PROCESS},
- {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE},
- {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED",
- NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
- {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT},
- {"NT_STATUS_INVALID_IMAGE_LE_FORMAT",
- NT_STATUS_INVALID_IMAGE_LE_FORMAT},
- {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ},
- {"NT_STATUS_INVALID_IMAGE_PROTECT",
- NT_STATUS_INVALID_IMAGE_PROTECT},
- {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16},
- {"NT_STATUS_LOGON_SERVER_CONFLICT",
- NT_STATUS_LOGON_SERVER_CONFLICT},
- {"NT_STATUS_TIME_DIFFERENCE_AT_DC",
- NT_STATUS_TIME_DIFFERENCE_AT_DC},
- {"NT_STATUS_SYNCHRONIZATION_REQUIRED",
- NT_STATUS_SYNCHRONIZATION_REQUIRED},
- {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND},
- {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED},
- {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED},
- {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND},
- {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND},
- {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT},
- {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT},
- {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT},
- {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES},
- {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED},
- {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT},
- {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION},
- {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS},
- {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED},
- {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE},
- {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION},
- {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE},
- {"NT_STATUS_PAGEFILE_CREATE_FAILED",
- NT_STATUS_PAGEFILE_CREATE_FAILED},
- {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE},
- {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL},
- {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE},
- {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT",
- NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
- {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN},
- {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT},
- {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED},
- {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR},
- {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME},
- {"NT_STATUS_SERIAL_NO_DEVICE_INITED",
- NT_STATUS_SERIAL_NO_DEVICE_INITED},
- {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS},
- {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS},
- {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS},
- {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS},
- {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED},
- {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS},
- {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG},
- {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR},
- {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE},
- {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS},
- {"NT_STATUS_LOGON_TYPE_NOT_GRANTED",
- NT_STATUS_LOGON_TYPE_NOT_GRANTED},
- {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE},
- {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED",
- NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
- {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR",
- NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
- {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER},
- {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY",
- NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
- {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER},
- {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER},
- {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER},
- {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME},
- {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND",
- NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
- {"NT_STATUS_FLOPPY_WRONG_CYLINDER",
- NT_STATUS_FLOPPY_WRONG_CYLINDER},
- {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR},
- {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS},
- {"NT_STATUS_DISK_RECALIBRATE_FAILED",
- NT_STATUS_DISK_RECALIBRATE_FAILED},
- {"NT_STATUS_DISK_OPERATION_FAILED",
- NT_STATUS_DISK_OPERATION_FAILED},
- {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED},
- {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY},
- {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING},
- {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE},
- {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH},
- {"NT_STATUS_DEVICE_NOT_PARTITIONED",
- NT_STATUS_DEVICE_NOT_PARTITIONED},
- {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA},
- {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA",
- NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
- {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW},
- {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA},
- {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER},
- {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER},
- {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED},
- {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE},
- {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS},
- {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED",
- NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
- {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN},
- {"NT_STATUS_CHILD_MUST_BE_VOLATILE",
- NT_STATUS_CHILD_MUST_BE_VOLATILE},
- {"NT_STATUS_DEVICE_CONFIGURATION_ERROR",
- NT_STATUS_DEVICE_CONFIGURATION_ERROR},
- {"NT_STATUS_DRIVER_INTERNAL_ERROR",
- NT_STATUS_DRIVER_INTERNAL_ERROR},
- {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE},
- {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR},
- {"NT_STATUS_DEVICE_PROTOCOL_ERROR",
- NT_STATUS_DEVICE_PROTOCOL_ERROR},
- {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER},
- {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL},
- {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE},
- {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET},
- {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT},
- {"NT_STATUS_TRUSTED_DOMAIN_FAILURE",
- NT_STATUS_TRUSTED_DOMAIN_FAILURE},
- {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE",
- NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
- {"NT_STATUS_EVENTLOG_FILE_CORRUPT",
- NT_STATUS_EVENTLOG_FILE_CORRUPT},
- {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START},
- {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE},
- {"NT_STATUS_MUTANT_LIMIT_EXCEEDED",
- NT_STATUS_MUTANT_LIMIT_EXCEEDED},
- {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED},
- {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED},
- {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK},
- {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT",
- NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
- {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT},
- {"NT_STATUS_EVENTLOG_FILE_CHANGED",
- NT_STATUS_EVENTLOG_FILE_CHANGED},
- {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
- NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
- {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
- NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
- {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
- NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
- {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT",
- NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
- {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED},
- {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY},
- {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED},
- {"NT_STATUS_RESOURCE_LANG_NOT_FOUND",
- NT_STATUS_RESOURCE_LANG_NOT_FOUND},
- {"NT_STATUS_INSUFF_SERVER_RESOURCES",
- NT_STATUS_INSUFF_SERVER_RESOURCES},
- {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE},
- {"NT_STATUS_INVALID_ADDRESS_COMPONENT",
- NT_STATUS_INVALID_ADDRESS_COMPONENT},
- {"NT_STATUS_INVALID_ADDRESS_WILDCARD",
- NT_STATUS_INVALID_ADDRESS_WILDCARD},
- {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES},
- {"NT_STATUS_ADDRESS_ALREADY_EXISTS",
- NT_STATUS_ADDRESS_ALREADY_EXISTS},
- {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED},
- {"NT_STATUS_CONNECTION_DISCONNECTED",
- NT_STATUS_CONNECTION_DISCONNECTED},
- {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET},
- {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES},
- {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED},
- {"NT_STATUS_TRANSACTION_TIMED_OUT",
- NT_STATUS_TRANSACTION_TIMED_OUT},
- {"NT_STATUS_TRANSACTION_NO_RELEASE",
- NT_STATUS_TRANSACTION_NO_RELEASE},
- {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH},
- {"NT_STATUS_TRANSACTION_RESPONDED",
- NT_STATUS_TRANSACTION_RESPONDED},
- {"NT_STATUS_TRANSACTION_INVALID_ID",
- NT_STATUS_TRANSACTION_INVALID_ID},
- {"NT_STATUS_TRANSACTION_INVALID_TYPE",
- NT_STATUS_TRANSACTION_INVALID_TYPE},
- {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION},
- {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION},
- {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE",
- NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
- {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED},
- {"NT_STATUS_SYSTEM_PROCESS_TERMINATED",
- NT_STATUS_SYSTEM_PROCESS_TERMINATED},
- {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED},
- {"NT_STATUS_NO_BROWSER_SERVERS_FOUND",
- NT_STATUS_NO_BROWSER_SERVERS_FOUND},
- {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR},
- {"NT_STATUS_DRIVER_CANCEL_TIMEOUT",
- NT_STATUS_DRIVER_CANCEL_TIMEOUT},
- {"NT_STATUS_REPLY_MESSAGE_MISMATCH",
- NT_STATUS_REPLY_MESSAGE_MISMATCH},
- {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT},
- {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH",
- NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
- {"NT_STATUS_LOST_WRITEBEHIND_DATA",
- NT_STATUS_LOST_WRITEBEHIND_DATA},
- {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID",
- NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
- {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE},
- {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND},
- {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM},
- {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE},
- {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ},
- {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK},
- {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID},
- {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS},
- {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE},
- {"NT_STATUS_RETRY", NT_STATUS_RETRY},
- {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE},
- {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET},
- {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND},
- {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW},
- {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT},
- {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
- NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
- {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT},
- {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE},
- {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED},
- {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT},
- {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED",
- NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
- {"NT_STATUS_ADDRESS_NOT_ASSOCIATED",
- NT_STATUS_ADDRESS_NOT_ASSOCIATED},
- {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID},
- {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE},
- {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE},
- {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE},
- {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE},
- {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE},
- {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED},
- {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED},
- {"NT_STATUS_BAD_COMPRESSION_BUFFER",
- NT_STATUS_BAD_COMPRESSION_BUFFER},
- {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE},
- {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED},
- {"NT_STATUS_TIMER_RESOLUTION_NOT_SET",
- NT_STATUS_TIMER_RESOLUTION_NOT_SET},
- {"NT_STATUS_CONNECTION_COUNT_LIMIT",
- NT_STATUS_CONNECTION_COUNT_LIMIT},
- {"NT_STATUS_LOGIN_TIME_RESTRICTION",
- NT_STATUS_LOGIN_TIME_RESTRICTION},
- {"NT_STATUS_LOGIN_WKSTA_RESTRICTION",
- NT_STATUS_LOGIN_WKSTA_RESTRICTION},
- {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH},
- {"NT_STATUS_INSUFFICIENT_LOGON_INFO",
- NT_STATUS_INSUFFICIENT_LOGON_INFO},
- {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT},
- {"NT_STATUS_BAD_SERVICE_ENTRYPOINT",
- NT_STATUS_BAD_SERVICE_ENTRYPOINT},
- {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST},
- {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1},
- {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2},
- {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT},
- {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED},
- {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE},
- {"NT_STATUS_LICENSE_QUOTA_EXCEEDED",
- NT_STATUS_LICENSE_QUOTA_EXCEEDED},
- {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT},
- {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT},
- {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT},
- {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE},
- {"NT_STATUS_UNSUPPORTED_COMPRESSION",
- NT_STATUS_UNSUPPORTED_COMPRESSION},
- {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE},
- {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH",
- NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
- {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND",
- NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
- {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND",
- NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
- {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED},
- {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS},
- {"NT_STATUS_QUOTA_LIST_INCONSISTENT",
- NT_STATUS_QUOTA_LIST_INCONSISTENT},
- {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
- {"NT_STATUS_NOT_A_REPARSE_POINT", NT_STATUS_NOT_A_REPARSE_POINT},
- {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
- {"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES},
- {"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED},
- {"NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB},
- {NULL, 0}
-};
diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h
index 180602c22355..a542029c6d34 100644
--- a/fs/smb/client/nterr.h
+++ b/fs/smb/client/nterr.h
@@ -15,538 +15,561 @@
#ifndef _NTERR_H
#define _NTERR_H
-struct nt_err_code_struct {
- char *nt_errstr;
- __u32 nt_errcode;
+/* NT status -> dos error map */
+struct ntstatus_to_dos_err {
+ __u8 dos_class;
+ __u16 dos_code;
+ __u32 ntstatus;
+ const char *nt_errstr;
};
-extern const struct nt_err_code_struct nt_errs[];
-
-/* Win32 Status codes. */
-#define NT_STATUS_MORE_ENTRIES 0x0105
+/* Win32 Error Codes. */
#define NT_ERROR_INVALID_PARAMETER 0x0057
#define NT_ERROR_INSUFFICIENT_BUFFER 0x007a
-#define NT_STATUS_1804 0x070c
-#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c
+#define NT_ERROR_INVALID_DATATYPE 0x070c
/*
- * Win32 Error codes extracted using a loop in smbclient then printing a netmon
+ * NTSTATUS Values extracted using a loop in smbclient then printing a netmon
* sniff to a file.
+ *
+ * The comment at the end of each definition indicates `dos_class`
+ * and `dos_code` fields of the `ntstatus_to_dos_map` array; it is
+ * used to generate the `smb1_mapping_table.c` file.
*/
-#define NT_STATUS_OK 0x0000
-#define NT_STATUS_SOME_UNMAPPED 0x0107
-#define NT_STATUS_BUFFER_OVERFLOW 0x80000005
-#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
-#define NT_STATUS_MEDIA_CHANGED 0x8000001c
-#define NT_STATUS_END_OF_MEDIA 0x8000001e
-#define NT_STATUS_MEDIA_CHECK 0x80000020
-#define NT_STATUS_NO_DATA_DETECTED 0x8000001c
-#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d
-#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288
-#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288
-#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
-#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
-#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
-#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004
-#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005
-#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006
-#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007
-#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008
-#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009
-#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a
-#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b
-#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c
-#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d
-#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e
-#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f
-#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010
-#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011
-#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012
-#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013
-#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014
-#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015
-#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016
-#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017
-#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018
-#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019
-#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a
-#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b
-#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c
-#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d
-#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e
-#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f
-#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020
-#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021
-#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022
-#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023
-#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024
-#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025
-#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026
-#define NT_STATUS_UNWIND 0xC0000000 | 0x0027
-#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028
-#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029
-#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a
-#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b
-#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c
-#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d
-#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e
-#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f
-#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030
-#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031
-#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032
-#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033
-#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034
-#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035
-#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036
-#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037
-#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038
-#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039
-#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a
-#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b
-#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c
-#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d
-#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e
-#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f
-#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040
-#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041
-#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042
-#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043
-#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044
-#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045
-#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046
-#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047
-#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048
-#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049
-#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a
-#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b
-#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c
-#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d
-#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e
-#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f
-#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050
-#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051
-#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052
-#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053
-#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054
-#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055
-#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056
-#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057
-#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058
-#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059
-#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a
-#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b
-#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c
-#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d
-#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e
-#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f
-#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060
-#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061
-#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062
-#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063
-#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064
-#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065
-#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066
-#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067
-#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068
-#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069
-#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a
-#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b
-#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c
-#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d
-#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e
-#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f
-#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070
-#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071
-#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072
-#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073
-#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074
-#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075
-#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076
-#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077
-#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078
-#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079
-#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a
-#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b
-#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c
-#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d
-#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e
-#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f
-#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080
-#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081
-#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082
-#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083
-#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084
-#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085
-#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086
-#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087
-#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088
-#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089
-#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a
-#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b
-#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c
-#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d
-#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e
-#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f
-#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090
-#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091
-#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092
-#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093
-#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094
-#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095
-#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096
-#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097
-#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098
-#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099
-#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a
-#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b
-#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c
-#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d
-#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e
-#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f
-#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0
-#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1
-#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2
-#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3
-#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4
-#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5
-#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6
-#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7
-#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8
-#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9
-#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa
-#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab
-#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac
-#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad
-#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae
-#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af
-#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0
-#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1
-#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2
-#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3
-#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4
-#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5
-#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6
-#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7
-#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8
-#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9
-#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba
-#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb
-#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc
-#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd
-#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be
-#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf
-#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0
-#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1
-#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2
-#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3
-#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4
-#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5
-#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6
-#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7
-#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8
-#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9
-#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca
-#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb
-#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc
-#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd
-#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce
-#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf
-#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0
-#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1
-#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2
-#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3
-#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4
-#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5
-#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6
-#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7
-#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8
-#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9
-#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da
-#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db
-#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc
-#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd
-#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de
-#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df
-#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0
-#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1
-#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2
-#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3
-#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4
-#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5
-#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6
-#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7
-#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8
-#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9
-#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea
-#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb
-#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec
-#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed
-#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee
-#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef
-#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0
-#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1
-#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2
-#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3
-#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4
-#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5
-#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6
-#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7
-#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8
-#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9
-#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa
-#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb
-#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc
-#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd
-#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe
-#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff
-#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101
-#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102
-#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103
-#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104
-#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105
-#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106
-#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107
-#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108
-#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109
-#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a
-#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b
-#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c
-#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d
-#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e
-#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f
-#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110
-#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111
-#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112
-#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113
-#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114
-#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115
-#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116
-#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117
-#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118
-#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119
-#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a
-#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b
-#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c
-#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d
-#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e
-#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f
-#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120
-#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121
-#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122
-#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123
-#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124
-#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125
-#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126
-#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127
-#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128
-#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129
-#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a
-#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b
-#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c
-#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d
-#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e
-#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f
-#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130
-#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131
-#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132
-#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133
-#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134
-#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135
-#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136
-#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137
-#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138
-#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139
-#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a
-#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b
-#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c
-#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d
-#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e
-#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f
-#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140
-#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141
-#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142
-#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143
-#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144
-#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145
-#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146
-#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147
-#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148
-#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149
-#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a
-#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b
-#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c
-#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d
-#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e
-#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f
-#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150
-#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151
-#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152
-#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153
-#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154
-#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155
-#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156
-#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157
-#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158
-#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159
-#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a
-#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b
-#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c
-#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d
-#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e
-#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f
-#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160
-#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161
-#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162
-#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163
-#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164
-#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165
-#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166
-#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167
-#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168
-#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169
-#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a
-#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b
-#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c
-#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d
-#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172
-#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173
-#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174
-#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175
-#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176
-#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177
-#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178
-#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a
-#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b
-#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c
-#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d
-#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e
-#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f
-#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180
-#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181
-#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182
-#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183
-#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184
-#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185
-#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186
-#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187
-#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188
-#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189
-#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a
-#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b
-#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c
-#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d
-#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e
-#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f
-#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190
-#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191
-#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192
-#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193
-#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194
-#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195
-#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196
-#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197
-#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198
-#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199
-#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a
-#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b
-#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c
-#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202
-#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203
-#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204
-#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205
-#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206
-#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207
-#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208
-#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209
-#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a
-#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b
-#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c
-#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d
-#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e
-#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f
-#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210
-#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211
-#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212
-#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213
-#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214
-#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215
-#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216
-#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217
-#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218
-#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219
-#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a
-#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b
-#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c
-#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d
-#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e
-#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f
-#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220
-#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221
-#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222
-#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223
-#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224
-#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225
-#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226
-#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227
-#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228
-#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229
-#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a
-#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b
-#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c
-#define NT_STATUS_RETRY 0xC0000000 | 0x022d
-#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e
-#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f
-#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230
-#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231
-#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232
-#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233
-#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234
-#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235
-#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236
-#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237
-#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238
-#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239
-#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a
-#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b
-#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c
-#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d
-#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e
-#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f
-#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240
-#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241
-#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242
-#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243
-#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244
-#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245
-#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246
-#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247
-#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248
-#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249
-#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250
-#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251
-#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252
-#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253
-#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254
-#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255
-#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256
-#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257
-#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258
-#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259
-#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a
-#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b
-#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c
-#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e
-#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f
-#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260
-#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261
-#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262
-#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263
-#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264
-#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265
-#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266
-#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267
-#define NT_STATUS_NOT_A_REPARSE_POINT 0xC0000000 | 0x0275
-#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */
+#define NT_STATUS_OK 0x0000 // SUCCESS, 0
+#define NT_STATUS_PENDING 0x0103 // ERRHRD, ERRgeneral
+#define NT_STATUS_MORE_ENTRIES 0x0105 // ERRHRD, ERRgeneral
+#define NT_STATUS_SOME_NOT_MAPPED 0x0107 // ERRHRD, ERRgeneral
+#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c // ERRSRV, ERR_NOTIFY_ENUM_DIR
+#define NT_STATUS_BUFFER_OVERFLOW 0x80000005 // ERRDOS, ERRmoredata
+#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a // ERRHRD, ERRgeneral
+#define NT_STATUS_MEDIA_CHANGED 0x8000001c // ERRHRD, ERRgeneral
+#define NT_STATUS_END_OF_MEDIA 0x8000001e // ERRHRD, ERRgeneral
+#define NT_STATUS_MEDIA_CHECK 0x80000020 // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_DATA_DETECTED 0x80000022 // ERRHRD, ERRgeneral
+#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d // ERRDOS, ERRsymlink
+#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 // ERRHRD, ERRgeneral
+#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000289 // ERRHRD, ERRgeneral
+#define NT_STATUS_UNSUCCESSFUL (0xC0000000 | 0x0001) // ERRDOS, ERRgeneral
+#define NT_STATUS_NOT_IMPLEMENTED (0xC0000000 | 0x0002) // ERRDOS, ERRbadfunc
+#define NT_STATUS_INVALID_INFO_CLASS (0xC0000000 | 0x0003) // ERRDOS, ERRbadpipe
+#define NT_STATUS_INFO_LENGTH_MISMATCH (0xC0000000 | 0x0004) // ERRDOS, 24
+#define NT_STATUS_ACCESS_VIOLATION (0xC0000000 | 0x0005) // ERRHRD, ERRgeneral
+#define NT_STATUS_IN_PAGE_ERROR (0xC0000000 | 0x0006) // ERRHRD, ERRgeneral
+#define NT_STATUS_PAGEFILE_QUOTA (0xC0000000 | 0x0007) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_HANDLE (0xC0000000 | 0x0008) // ERRDOS, ERRbadfid
+#define NT_STATUS_BAD_INITIAL_STACK (0xC0000000 | 0x0009) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_INITIAL_PC (0xC0000000 | 0x000a) // ERRDOS, 193
+#define NT_STATUS_INVALID_CID (0xC0000000 | 0x000b) // ERRDOS, 87
+#define NT_STATUS_TIMER_NOT_CANCELED (0xC0000000 | 0x000c) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PARAMETER (0xC0000000 | 0x000d) // ERRDOS, 87
+#define NT_STATUS_NO_SUCH_DEVICE (0xC0000000 | 0x000e) // ERRDOS, ERRbadfile
+#define NT_STATUS_NO_SUCH_FILE (0xC0000000 | 0x000f) // ERRDOS, ERRbadfile
+#define NT_STATUS_INVALID_DEVICE_REQUEST (0xC0000000 | 0x0010) // ERRDOS, ERRbadfunc
+#define NT_STATUS_END_OF_FILE (0xC0000000 | 0x0011) // ERRDOS, 38
+#define NT_STATUS_WRONG_VOLUME (0xC0000000 | 0x0012) // ERRDOS, 34
+#define NT_STATUS_NO_MEDIA_IN_DEVICE (0xC0000000 | 0x0013) // ERRDOS, 21
+#define NT_STATUS_UNRECOGNIZED_MEDIA (0xC0000000 | 0x0014) // ERRHRD, ERRgeneral
+#define NT_STATUS_NONEXISTENT_SECTOR (0xC0000000 | 0x0015) // ERRDOS, 27
+#define NT_STATUS_MORE_PROCESSING_REQUIRED (0xC0000000 | 0x0016) // ERRDOS, ERRmoredata
+#define NT_STATUS_NO_MEMORY (0xC0000000 | 0x0017) // ERRDOS, ERRnomem
+#define NT_STATUS_CONFLICTING_ADDRESSES (0xC0000000 | 0x0018) // ERRDOS, 487
+#define NT_STATUS_NOT_MAPPED_VIEW (0xC0000000 | 0x0019) // ERRDOS, 487
+#define NT_STATUS_UNABLE_TO_FREE_VM (0xC0000000 | 0x001a) // ERRDOS, 87
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION (0xC0000000 | 0x001b) // ERRDOS, 87
+#define NT_STATUS_INVALID_SYSTEM_SERVICE (0xC0000000 | 0x001c) // ERRDOS, 2142
+#define NT_STATUS_ILLEGAL_INSTRUCTION (0xC0000000 | 0x001d) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LOCK_SEQUENCE (0xC0000000 | 0x001e) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_VIEW_SIZE (0xC0000000 | 0x001f) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_FILE_FOR_SECTION (0xC0000000 | 0x0020) // ERRDOS, 193
+#define NT_STATUS_ALREADY_COMMITTED (0xC0000000 | 0x0021) // ERRDOS, ERRnoaccess
+#define NT_STATUS_ACCESS_DENIED (0xC0000000 | 0x0022) // ERRDOS, ERRnoaccess
+#define NT_STATUS_BUFFER_TOO_SMALL (0xC0000000 | 0x0023) // ERRDOS, 111
+#define NT_STATUS_OBJECT_TYPE_MISMATCH (0xC0000000 | 0x0024) // ERRDOS, ERRbadfid
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION (0xC0000000 | 0x0025) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_DISPOSITION (0xC0000000 | 0x0026) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNWIND (0xC0000000 | 0x0027) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_STACK (0xC0000000 | 0x0028) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_UNWIND_TARGET (0xC0000000 | 0x0029) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOT_LOCKED (0xC0000000 | 0x002a) // ERRDOS, 158
+#define NT_STATUS_PARITY_ERROR (0xC0000000 | 0x002b) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (0xC0000000 | 0x002c) // ERRDOS, 487
+#define NT_STATUS_NOT_COMMITTED (0xC0000000 | 0x002d) // ERRDOS, 487
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES (0xC0000000 | 0x002e) // ERRHRD, ERRgeneral
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG (0xC0000000 | 0x002f) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PARAMETER_MIX (0xC0000000 | 0x0030) // ERRDOS, 87
+#define NT_STATUS_INVALID_QUOTA_LOWER (0xC0000000 | 0x0031) // ERRHRD, ERRgeneral
+#define NT_STATUS_DISK_CORRUPT_ERROR (0xC0000000 | 0x0032) // ERRHRD, ERRgeneral
+#define NT_STATUS_OBJECT_NAME_INVALID (0xC0000000 | 0x0033) // ERRDOS, ERRbadfile
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND (0xC0000000 | 0x0034) // ERRDOS, ERRbadfile
+#define NT_STATUS_OBJECT_NAME_COLLISION (0xC0000000 | 0x0035) // ERRDOS, ERRalreadyexists
+#define NT_STATUS_HANDLE_NOT_WAITABLE (0xC0000000 | 0x0036) // ERRHRD, ERRgeneral
+#define NT_STATUS_PORT_DISCONNECTED (0xC0000000 | 0x0037) // ERRDOS, ERRbadfid
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED (0xC0000000 | 0x0038) // ERRHRD, ERRgeneral
+#define NT_STATUS_OBJECT_PATH_INVALID (0xC0000000 | 0x0039) // ERRDOS, 161
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND (0xC0000000 | 0x003a) // ERRDOS, ERRbadpath
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (0xC0000000 | 0x003b) // ERRDOS, 161
+#define NT_STATUS_DATA_OVERRUN (0xC0000000 | 0x003c) // ERRHRD, ERRgeneral
+#define NT_STATUS_DATA_LATE_ERROR (0xC0000000 | 0x003d) // ERRHRD, ERRgeneral
+#define NT_STATUS_DATA_ERROR (0xC0000000 | 0x003e) // ERRDOS, 23
+#define NT_STATUS_CRC_ERROR (0xC0000000 | 0x003f) // ERRDOS, 23
+#define NT_STATUS_SECTION_TOO_BIG (0xC0000000 | 0x0040) // ERRDOS, ERRnomem
+#define NT_STATUS_PORT_CONNECTION_REFUSED (0xC0000000 | 0x0041) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_PORT_HANDLE (0xC0000000 | 0x0042) // ERRDOS, ERRbadfid
+#define NT_STATUS_SHARING_VIOLATION (0xC0000000 | 0x0043) // ERRDOS, ERRbadshare
+#define NT_STATUS_QUOTA_EXCEEDED (0xC0000000 | 0x0044) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PAGE_PROTECTION (0xC0000000 | 0x0045) // ERRDOS, 87
+#define NT_STATUS_MUTANT_NOT_OWNED (0xC0000000 | 0x0046) // ERRDOS, 288
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (0xC0000000 | 0x0047) // ERRDOS, 298
+#define NT_STATUS_PORT_ALREADY_SET (0xC0000000 | 0x0048) // ERRDOS, 87
+#define NT_STATUS_SECTION_NOT_IMAGE (0xC0000000 | 0x0049) // ERRDOS, 87
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (0xC0000000 | 0x004a) // ERRDOS, 156
+#define NT_STATUS_THREAD_IS_TERMINATING (0xC0000000 | 0x004b) // ERRDOS, ERRnoaccess
+#define NT_STATUS_BAD_WORKING_SET_LIMIT (0xC0000000 | 0x004c) // ERRDOS, 87
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP (0xC0000000 | 0x004d) // ERRDOS, 87
+#define NT_STATUS_SECTION_PROTECTION (0xC0000000 | 0x004e) // ERRDOS, 87
+#define NT_STATUS_EAS_NOT_SUPPORTED (0xC0000000 | 0x004f) // ERRDOS, ERReasnotsupported
+#define NT_STATUS_EA_TOO_LARGE (0xC0000000 | 0x0050) // ERRDOS, 255
+#define NT_STATUS_NONEXISTENT_EA_ENTRY (0xC0000000 | 0x0051) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_EAS_ON_FILE (0xC0000000 | 0x0052) // ERRHRD, ERRgeneral
+#define NT_STATUS_EA_CORRUPT_ERROR (0xC0000000 | 0x0053) // ERRHRD, ERRgeneral
+#define NT_STATUS_FILE_LOCK_CONFLICT (0xC0000000 | 0x0054) // ERRDOS, ERRlock
+#define NT_STATUS_LOCK_NOT_GRANTED (0xC0000000 | 0x0055) // ERRDOS, ERRlock
+#define NT_STATUS_DELETE_PENDING (0xC0000000 | 0x0056) // ERRDOS, ERRbadfile
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (0xC0000000 | 0x0057) // ERRDOS, ERRunsup
+#define NT_STATUS_UNKNOWN_REVISION (0xC0000000 | 0x0058) // ERRHRD, ERRgeneral
+#define NT_STATUS_REVISION_MISMATCH (0xC0000000 | 0x0059) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_OWNER (0xC0000000 | 0x005a) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PRIMARY_GROUP (0xC0000000 | 0x005b) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_IMPERSONATION_TOKEN (0xC0000000 | 0x005c) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANT_DISABLE_MANDATORY (0xC0000000 | 0x005d) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_LOGON_SERVERS (0xC0000000 | 0x005e) // ERRDOS, 2215
+#define NT_STATUS_NO_SUCH_LOGON_SESSION (0xC0000000 | 0x005f) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_PRIVILEGE (0xC0000000 | 0x0060) // ERRHRD, ERRgeneral
+#define NT_STATUS_PRIVILEGE_NOT_HELD (0xC0000000 | 0x0061) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_ACCOUNT_NAME (0xC0000000 | 0x0062) // ERRHRD, ERRgeneral
+#define NT_STATUS_USER_EXISTS (0xC0000000 | 0x0063) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_USER (0xC0000000 | 0x0064) // ERRDOS, ERRnoaccess
+#define NT_STATUS_GROUP_EXISTS (0xC0000000 | 0x0065) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_GROUP (0xC0000000 | 0x0066) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEMBER_IN_GROUP (0xC0000000 | 0x0067) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEMBER_NOT_IN_GROUP (0xC0000000 | 0x0068) // ERRHRD, ERRgeneral
+#define NT_STATUS_LAST_ADMIN (0xC0000000 | 0x0069) // ERRHRD, ERRgeneral
+#define NT_STATUS_WRONG_PASSWORD (0xC0000000 | 0x006a) // ERRSRV, ERRbadpw
+#define NT_STATUS_ILL_FORMED_PASSWORD (0xC0000000 | 0x006b) // ERRHRD, ERRgeneral
+#define NT_STATUS_PASSWORD_RESTRICTION (0xC0000000 | 0x006c) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGON_FAILURE (0xC0000000 | 0x006d) // ERRDOS, ERRnoaccess
+#define NT_STATUS_ACCOUNT_RESTRICTION (0xC0000000 | 0x006e) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LOGON_HOURS (0xC0000000 | 0x006f) // ERRSRV, ERRbadLogonTime
+#define NT_STATUS_INVALID_WORKSTATION (0xC0000000 | 0x0070) // ERRSRV, ERRbadclient
+#define NT_STATUS_PASSWORD_EXPIRED (0xC0000000 | 0x0071) // ERRSRV, ERRpasswordExpired
+#define NT_STATUS_ACCOUNT_DISABLED (0xC0000000 | 0x0072) // ERRSRV, ERRaccountexpired
+#define NT_STATUS_NONE_MAPPED (0xC0000000 | 0x0073) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (0xC0000000 | 0x0074) // ERRHRD, ERRgeneral
+#define NT_STATUS_LUIDS_EXHAUSTED (0xC0000000 | 0x0075) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_SUB_AUTHORITY (0xC0000000 | 0x0076) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_ACL (0xC0000000 | 0x0077) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_SID (0xC0000000 | 0x0078) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_SECURITY_DESCR (0xC0000000 | 0x0079) // ERRHRD, ERRgeneral
+#define NT_STATUS_PROCEDURE_NOT_FOUND (0xC0000000 | 0x007a) // ERRDOS, 127
+#define NT_STATUS_INVALID_IMAGE_FORMAT (0xC0000000 | 0x007b) // ERRDOS, 193
+#define NT_STATUS_NO_TOKEN (0xC0000000 | 0x007c) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_INHERITANCE_ACL (0xC0000000 | 0x007d) // ERRHRD, ERRgeneral
+#define NT_STATUS_RANGE_NOT_LOCKED (0xC0000000 | 0x007e) // ERRDOS, 158
+#define NT_STATUS_DISK_FULL (0xC0000000 | 0x007f) // ERRDOS, 112
+#define NT_STATUS_SERVER_DISABLED (0xC0000000 | 0x0080) // ERRHRD, ERRgeneral
+#define NT_STATUS_SERVER_NOT_DISABLED (0xC0000000 | 0x0081) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (0xC0000000 | 0x0082) // ERRDOS, 68
+#define NT_STATUS_GUIDS_EXHAUSTED (0xC0000000 | 0x0083) // ERRDOS, 259
+#define NT_STATUS_INVALID_ID_AUTHORITY (0xC0000000 | 0x0084) // ERRHRD, ERRgeneral
+#define NT_STATUS_AGENTS_EXHAUSTED (0xC0000000 | 0x0085) // ERRDOS, 259
+#define NT_STATUS_INVALID_VOLUME_LABEL (0xC0000000 | 0x0086) // ERRDOS, 154
+#define NT_STATUS_SECTION_NOT_EXTENDED (0xC0000000 | 0x0087) // ERRDOS, 14
+#define NT_STATUS_NOT_MAPPED_DATA (0xC0000000 | 0x0088) // ERRDOS, 487
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (0xC0000000 | 0x0089) // ERRHRD, ERRgeneral
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (0xC0000000 | 0x008a) // ERRHRD, ERRgeneral
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (0xC0000000 | 0x008b) // ERRHRD, ERRgeneral
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (0xC0000000 | 0x008c) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND (0xC0000000 | 0x008d) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (0xC0000000 | 0x008e) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_INEXACT_RESULT (0xC0000000 | 0x008f) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_INVALID_OPERATION (0xC0000000 | 0x0090) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_OVERFLOW (0xC0000000 | 0x0091) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_STACK_CHECK (0xC0000000 | 0x0092) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOAT_UNDERFLOW (0xC0000000 | 0x0093) // ERRHRD, ERRgeneral
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (0xC0000000 | 0x0094) // ERRHRD, ERRgeneral
+#define NT_STATUS_INTEGER_OVERFLOW (0xC0000000 | 0x0095) // ERRDOS, 534
+#define NT_STATUS_PRIVILEGED_INSTRUCTION (0xC0000000 | 0x0096) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_PAGING_FILES (0xC0000000 | 0x0097) // ERRDOS, ERRnomem
+#define NT_STATUS_FILE_INVALID (0xC0000000 | 0x0098) // ERRHRD, ERRgeneral
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (0xC0000000 | 0x0099) // ERRHRD, ERRgeneral
+#define NT_STATUS_INSUFFICIENT_RESOURCES (0xC0000000 | 0x009a) // ERRDOS, ERRnoresource
+#define NT_STATUS_DFS_EXIT_PATH_FOUND (0xC0000000 | 0x009b) // ERRDOS, ERRbadpath
+#define NT_STATUS_DEVICE_DATA_ERROR (0xC0000000 | 0x009c) // ERRDOS, 23
+#define NT_STATUS_DEVICE_NOT_CONNECTED (0xC0000000 | 0x009d) // ERRHRD, ERRgeneral
+#define NT_STATUS_DEVICE_POWER_FAILURE (0xC0000000 | 0x009e) // ERRDOS, 21
+#define NT_STATUS_FREE_VM_NOT_AT_BASE (0xC0000000 | 0x009f) // ERRDOS, 487
+#define NT_STATUS_MEMORY_NOT_ALLOCATED (0xC0000000 | 0x00a0) // ERRDOS, 487
+#define NT_STATUS_WORKING_SET_QUOTA (0xC0000000 | 0x00a1) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEDIA_WRITE_PROTECTED (0xC0000000 | 0x00a2) // ERRDOS, 19
+#define NT_STATUS_DEVICE_NOT_READY (0xC0000000 | 0x00a3) // ERRDOS, 21
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (0xC0000000 | 0x00a4) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL (0xC0000000 | 0x00a5) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANT_OPEN_ANONYMOUS (0xC0000000 | 0x00a6) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_VALIDATION_CLASS (0xC0000000 | 0x00a7) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_TOKEN_TYPE (0xC0000000 | 0x00a8) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD (0xC0000000 | 0x00a9) // ERRDOS, 87
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT (0xC0000000 | 0x00aa) // ERRHRD, ERRgeneral
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE (0xC0000000 | 0x00ab) // ERRDOS, ERRpipebusy
+#define NT_STATUS_PIPE_NOT_AVAILABLE (0xC0000000 | 0x00ac) // ERRDOS, ERRpipebusy
+#define NT_STATUS_INVALID_PIPE_STATE (0xC0000000 | 0x00ad) // ERRDOS, ERRbadpipe
+#define NT_STATUS_PIPE_BUSY (0xC0000000 | 0x00ae) // ERRDOS, ERRpipebusy
+#define NT_STATUS_ILLEGAL_FUNCTION (0xC0000000 | 0x00af) // ERRDOS, ERRbadfunc
+#define NT_STATUS_PIPE_DISCONNECTED (0xC0000000 | 0x00b0) // ERRDOS, ERRnotconnected
+#define NT_STATUS_PIPE_CLOSING (0xC0000000 | 0x00b1) // ERRDOS, ERRpipeclosing
+#define NT_STATUS_PIPE_CONNECTED (0xC0000000 | 0x00b2) // ERRHRD, ERRgeneral
+#define NT_STATUS_PIPE_LISTENING (0xC0000000 | 0x00b3) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_READ_MODE (0xC0000000 | 0x00b4) // ERRDOS, ERRbadpipe
+#define NT_STATUS_IO_TIMEOUT (0xC0000000 | 0x00b5) // ERRDOS, 121
+#define NT_STATUS_FILE_FORCED_CLOSED (0xC0000000 | 0x00b6) // ERRDOS, 38
+#define NT_STATUS_PROFILING_NOT_STARTED (0xC0000000 | 0x00b7) // ERRHRD, ERRgeneral
+#define NT_STATUS_PROFILING_NOT_STOPPED (0xC0000000 | 0x00b8) // ERRHRD, ERRgeneral
+#define NT_STATUS_COULD_NOT_INTERPRET (0xC0000000 | 0x00b9) // ERRHRD, ERRgeneral
+#define NT_STATUS_FILE_IS_A_DIRECTORY (0xC0000000 | 0x00ba) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NOT_SUPPORTED (0xC0000000 | 0x00bb) // ERRDOS, ERRunsup
+#define NT_STATUS_REMOTE_NOT_LISTENING (0xC0000000 | 0x00bc) // ERRDOS, 51
+#define NT_STATUS_DUPLICATE_NAME (0xC0000000 | 0x00bd) // ERRDOS, 52
+#define NT_STATUS_BAD_NETWORK_PATH (0xC0000000 | 0x00be) // ERRDOS, 53
+#define NT_STATUS_NETWORK_BUSY (0xC0000000 | 0x00bf) // ERRDOS, 54
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST (0xC0000000 | 0x00c0) // ERRDOS, 55
+#define NT_STATUS_TOO_MANY_COMMANDS (0xC0000000 | 0x00c1) // ERRDOS, 56
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR (0xC0000000 | 0x00c2) // ERRDOS, 57
+#define NT_STATUS_INVALID_NETWORK_RESPONSE (0xC0000000 | 0x00c3) // ERRDOS, 58
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (0xC0000000 | 0x00c4) // ERRDOS, 59
+#define NT_STATUS_BAD_REMOTE_ADAPTER (0xC0000000 | 0x00c5) // ERRDOS, 60
+#define NT_STATUS_PRINT_QUEUE_FULL (0xC0000000 | 0x00c6) // ERRDOS, 61
+#define NT_STATUS_NO_SPOOL_SPACE (0xC0000000 | 0x00c7) // ERRDOS, 62
+#define NT_STATUS_PRINT_CANCELLED (0xC0000000 | 0x00c8) // ERRDOS, 63
+#define NT_STATUS_NETWORK_NAME_DELETED (0xC0000000 | 0x00c9) // ERRDOS, 64
+#define NT_STATUS_NETWORK_ACCESS_DENIED (0xC0000000 | 0x00ca) // ERRDOS, 65
+#define NT_STATUS_BAD_DEVICE_TYPE (0xC0000000 | 0x00cb) // ERRDOS, 66
+#define NT_STATUS_BAD_NETWORK_NAME (0xC0000000 | 0x00cc) // ERRDOS, ERRnosuchshare
+#define NT_STATUS_TOO_MANY_NAMES (0xC0000000 | 0x00cd) // ERRDOS, 68
+#define NT_STATUS_TOO_MANY_SESSIONS (0xC0000000 | 0x00ce) // ERRDOS, 69
+#define NT_STATUS_SHARING_PAUSED (0xC0000000 | 0x00cf) // ERRDOS, 70
+#define NT_STATUS_REQUEST_NOT_ACCEPTED (0xC0000000 | 0x00d0) // ERRDOS, 71
+#define NT_STATUS_REDIRECTOR_PAUSED (0xC0000000 | 0x00d1) // ERRDOS, 72
+#define NT_STATUS_NET_WRITE_FAULT (0xC0000000 | 0x00d2) // ERRDOS, 88
+#define NT_STATUS_PROFILING_AT_LIMIT (0xC0000000 | 0x00d3) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOT_SAME_DEVICE (0xC0000000 | 0x00d4) // ERRDOS, ERRdiffdevice
+#define NT_STATUS_FILE_RENAMED (0xC0000000 | 0x00d5) // ERRDOS, ERRnoaccess
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (0xC0000000 | 0x00d6) // ERRDOS, 240
+#define NT_STATUS_NO_SECURITY_ON_OBJECT (0xC0000000 | 0x00d7) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANT_WAIT (0xC0000000 | 0x00d8) // ERRHRD, ERRgeneral
+#define NT_STATUS_PIPE_EMPTY (0xC0000000 | 0x00d9) // ERRDOS, ERRpipeclosing
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (0xC0000000 | 0x00da) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANT_TERMINATE_SELF (0xC0000000 | 0x00db) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_SERVER_STATE (0xC0000000 | 0x00dc) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_DOMAIN_STATE (0xC0000000 | 0x00dd) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_DOMAIN_ROLE (0xC0000000 | 0x00de) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_DOMAIN (0xC0000000 | 0x00df) // ERRHRD, ERRgeneral
+#define NT_STATUS_DOMAIN_EXISTS (0xC0000000 | 0x00e0) // ERRHRD, ERRgeneral
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (0xC0000000 | 0x00e1) // ERRHRD, ERRgeneral
+#define NT_STATUS_OPLOCK_NOT_GRANTED (0xC0000000 | 0x00e2) // ERRDOS, 300
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (0xC0000000 | 0x00e3) // ERRDOS, 301
+#define NT_STATUS_INTERNAL_DB_CORRUPTION (0xC0000000 | 0x00e4) // ERRHRD, ERRgeneral
+#define NT_STATUS_INTERNAL_ERROR (0xC0000000 | 0x00e5) // ERRHRD, ERRgeneral
+#define NT_STATUS_GENERIC_NOT_MAPPED (0xC0000000 | 0x00e6) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (0xC0000000 | 0x00e7) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_USER_BUFFER (0xC0000000 | 0x00e8) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNEXPECTED_IO_ERROR (0xC0000000 | 0x00e9) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (0xC0000000 | 0x00ea) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (0xC0000000 | 0x00eb) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (0xC0000000 | 0x00ec) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOT_LOGON_PROCESS (0xC0000000 | 0x00ed) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGON_SESSION_EXISTS (0xC0000000 | 0x00ee) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PARAMETER_1 (0xC0000000 | 0x00ef) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_2 (0xC0000000 | 0x00f0) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_3 (0xC0000000 | 0x00f1) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_4 (0xC0000000 | 0x00f2) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_5 (0xC0000000 | 0x00f3) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_6 (0xC0000000 | 0x00f4) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_7 (0xC0000000 | 0x00f5) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_8 (0xC0000000 | 0x00f6) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_9 (0xC0000000 | 0x00f7) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_10 (0xC0000000 | 0x00f8) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_11 (0xC0000000 | 0x00f9) // ERRDOS, 87
+#define NT_STATUS_INVALID_PARAMETER_12 (0xC0000000 | 0x00fa) // ERRDOS, 87
+#define NT_STATUS_REDIRECTOR_NOT_STARTED (0xC0000000 | 0x00fb) // ERRDOS, ERRbadpath
+#define NT_STATUS_REDIRECTOR_STARTED (0xC0000000 | 0x00fc) // ERRHRD, ERRgeneral
+#define NT_STATUS_STACK_OVERFLOW (0xC0000000 | 0x00fd) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_PACKAGE (0xC0000000 | 0x00fe) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_FUNCTION_TABLE (0xC0000000 | 0x00ff) // ERRHRD, ERRgeneral
+#define NT_STATUS_VARIABLE_NOT_FOUND (0xC0000000 | 0x0100) // ERRDOS, 203
+#define NT_STATUS_DIRECTORY_NOT_EMPTY (0xC0000000 | 0x0101) // ERRDOS, 145
+#define NT_STATUS_FILE_CORRUPT_ERROR (0xC0000000 | 0x0102) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOT_A_DIRECTORY (0xC0000000 | 0x0103) // ERRDOS, 267
+#define NT_STATUS_BAD_LOGON_SESSION_STATE (0xC0000000 | 0x0104) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGON_SESSION_COLLISION (0xC0000000 | 0x0105) // ERRHRD, ERRgeneral
+#define NT_STATUS_NAME_TOO_LONG (0xC0000000 | 0x0106) // ERRDOS, 206
+#define NT_STATUS_FILES_OPEN (0xC0000000 | 0x0107) // ERRDOS, 2401
+#define NT_STATUS_CONNECTION_IN_USE (0xC0000000 | 0x0108) // ERRDOS, 2404
+#define NT_STATUS_MESSAGE_NOT_FOUND (0xC0000000 | 0x0109) // ERRHRD, ERRgeneral
+#define NT_STATUS_PROCESS_IS_TERMINATING (0xC0000000 | 0x010a) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_LOGON_TYPE (0xC0000000 | 0x010b) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_GUID_TRANSLATION (0xC0000000 | 0x010c) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANNOT_IMPERSONATE (0xC0000000 | 0x010d) // ERRHRD, ERRgeneral
+#define NT_STATUS_IMAGE_ALREADY_LOADED (0xC0000000 | 0x010e) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_NOT_PRESENT (0xC0000000 | 0x010f) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_LID_NOT_EXIST (0xC0000000 | 0x0110) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (0xC0000000 | 0x0111) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_NOT_LID_OWNER (0xC0000000 | 0x0112) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_INVALID_COMMAND (0xC0000000 | 0x0113) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_INVALID_LID (0xC0000000 | 0x0114) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (0xC0000000 | 0x0115) // ERRHRD, ERRgeneral
+#define NT_STATUS_ABIOS_INVALID_SELECTOR (0xC0000000 | 0x0116) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_LDT (0xC0000000 | 0x0117) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LDT_SIZE (0xC0000000 | 0x0118) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LDT_OFFSET (0xC0000000 | 0x0119) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR (0xC0000000 | 0x011a) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (0xC0000000 | 0x011b) // ERRDOS, 193
+#define NT_STATUS_RXACT_INVALID_STATE (0xC0000000 | 0x011c) // ERRHRD, ERRgeneral
+#define NT_STATUS_RXACT_COMMIT_FAILURE (0xC0000000 | 0x011d) // ERRHRD, ERRgeneral
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (0xC0000000 | 0x011e) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_OPENED_FILES (0xC0000000 | 0x011f) // ERRDOS, ERRnofids
+#define NT_STATUS_CANCELLED (0xC0000000 | 0x0120) // ERRHRD, ERRgeneral
+#define NT_STATUS_CANNOT_DELETE (0xC0000000 | 0x0121) // ERRDOS, ERRnoaccess
+#define NT_STATUS_INVALID_COMPUTER_NAME (0xC0000000 | 0x0122) // ERRHRD, ERRgeneral
+#define NT_STATUS_FILE_DELETED (0xC0000000 | 0x0123) // ERRDOS, ERRnoaccess
+#define NT_STATUS_SPECIAL_ACCOUNT (0xC0000000 | 0x0124) // ERRHRD, ERRgeneral
+#define NT_STATUS_SPECIAL_GROUP (0xC0000000 | 0x0125) // ERRHRD, ERRgeneral
+#define NT_STATUS_SPECIAL_USER (0xC0000000 | 0x0126) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP (0xC0000000 | 0x0127) // ERRHRD, ERRgeneral
+#define NT_STATUS_FILE_CLOSED (0xC0000000 | 0x0128) // ERRDOS, ERRbadfid
+#define NT_STATUS_TOO_MANY_THREADS (0xC0000000 | 0x0129) // ERRHRD, ERRgeneral
+#define NT_STATUS_THREAD_NOT_IN_PROCESS (0xC0000000 | 0x012a) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOKEN_ALREADY_IN_USE (0xC0000000 | 0x012b) // ERRHRD, ERRgeneral
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (0xC0000000 | 0x012c) // ERRHRD, ERRgeneral
+#define NT_STATUS_COMMITMENT_LIMIT (0xC0000000 | 0x012d) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (0xC0000000 | 0x012e) // ERRDOS, 193
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ (0xC0000000 | 0x012f) // ERRDOS, 193
+#define NT_STATUS_INVALID_IMAGE_PROTECT (0xC0000000 | 0x0130) // ERRDOS, 193
+#define NT_STATUS_INVALID_IMAGE_WIN_16 (0xC0000000 | 0x0131) // ERRDOS, 193
+#define NT_STATUS_LOGON_SERVER_CONFLICT (0xC0000000 | 0x0132) // ERRHRD, ERRgeneral
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC (0xC0000000 | 0x0133) // ERRHRD, ERRgeneral
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED (0xC0000000 | 0x0134) // ERRHRD, ERRgeneral
+#define NT_STATUS_DLL_NOT_FOUND (0xC0000000 | 0x0135) // ERRDOS, 126
+#define NT_STATUS_OPEN_FAILED (0xC0000000 | 0x0136) // ERRHRD, ERRgeneral
+#define NT_STATUS_IO_PRIVILEGE_FAILED (0xC0000000 | 0x0137) // ERRHRD, ERRgeneral
+#define NT_STATUS_ORDINAL_NOT_FOUND (0xC0000000 | 0x0138) // ERRDOS, 182
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0139) // ERRDOS, 127
+#define NT_STATUS_CONTROL_C_EXIT (0xC0000000 | 0x013a) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOCAL_DISCONNECT (0xC0000000 | 0x013b) // ERRDOS, 64
+#define NT_STATUS_REMOTE_DISCONNECT (0xC0000000 | 0x013c) // ERRDOS, 64
+#define NT_STATUS_REMOTE_RESOURCES (0xC0000000 | 0x013d) // ERRDOS, 51
+#define NT_STATUS_LINK_FAILED (0xC0000000 | 0x013e) // ERRDOS, 59
+#define NT_STATUS_LINK_TIMEOUT (0xC0000000 | 0x013f) // ERRDOS, 59
+#define NT_STATUS_INVALID_CONNECTION (0xC0000000 | 0x0140) // ERRDOS, 59
+#define NT_STATUS_INVALID_ADDRESS (0xC0000000 | 0x0141) // ERRDOS, 59
+#define NT_STATUS_DLL_INIT_FAILED (0xC0000000 | 0x0142) // ERRHRD, ERRgeneral
+#define NT_STATUS_MISSING_SYSTEMFILE (0xC0000000 | 0x0143) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNHANDLED_EXCEPTION (0xC0000000 | 0x0144) // ERRHRD, ERRgeneral
+#define NT_STATUS_APP_INIT_FAILURE (0xC0000000 | 0x0145) // ERRHRD, ERRgeneral
+#define NT_STATUS_PAGEFILE_CREATE_FAILED (0xC0000000 | 0x0146) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_PAGEFILE (0xC0000000 | 0x0147) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LEVEL (0xC0000000 | 0x0148) // ERRDOS, 124
+#define NT_STATUS_WRONG_PASSWORD_CORE (0xC0000000 | 0x0149) // ERRDOS, 86
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (0xC0000000 | 0x014a) // ERRHRD, ERRgeneral
+#define NT_STATUS_PIPE_BROKEN (0xC0000000 | 0x014b) // ERRDOS, 109
+#define NT_STATUS_REGISTRY_CORRUPT (0xC0000000 | 0x014c) // ERRHRD, ERRgeneral
+#define NT_STATUS_REGISTRY_IO_FAILED (0xC0000000 | 0x014d) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_EVENT_PAIR (0xC0000000 | 0x014e) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNRECOGNIZED_VOLUME (0xC0000000 | 0x014f) // ERRHRD, ERRgeneral
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED (0xC0000000 | 0x0150) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_ALIAS (0xC0000000 | 0x0151) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS (0xC0000000 | 0x0152) // ERRHRD, ERRgeneral
+#define NT_STATUS_MEMBER_IN_ALIAS (0xC0000000 | 0x0153) // ERRHRD, ERRgeneral
+#define NT_STATUS_ALIAS_EXISTS (0xC0000000 | 0x0154) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGON_NOT_GRANTED (0xC0000000 | 0x0155) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_SECRETS (0xC0000000 | 0x0156) // ERRHRD, ERRgeneral
+#define NT_STATUS_SECRET_TOO_LONG (0xC0000000 | 0x0157) // ERRHRD, ERRgeneral
+#define NT_STATUS_INTERNAL_DB_ERROR (0xC0000000 | 0x0158) // ERRHRD, ERRgeneral
+#define NT_STATUS_FULLSCREEN_MODE (0xC0000000 | 0x0159) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS (0xC0000000 | 0x015a) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (0xC0000000 | 0x015b) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NOT_REGISTRY_FILE (0xC0000000 | 0x015c) // ERRHRD, ERRgeneral
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x015d) // ERRHRD, ERRgeneral
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (0xC0000000 | 0x015e) // ERRHRD, ERRgeneral
+#define NT_STATUS_FT_MISSING_MEMBER (0xC0000000 | 0x015f) // ERRHRD, ERRgeneral
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (0xC0000000 | 0x0160) // ERRHRD, ERRgeneral
+#define NT_STATUS_ILLEGAL_CHARACTER (0xC0000000 | 0x0161) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNMAPPABLE_CHARACTER (0xC0000000 | 0x0162) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNDEFINED_CHARACTER (0xC0000000 | 0x0163) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOPPY_VOLUME (0xC0000000 | 0x0164) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (0xC0000000 | 0x0165) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER (0xC0000000 | 0x0166) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (0xC0000000 | 0x0167) // ERRHRD, ERRgeneral
+#define NT_STATUS_FLOPPY_BAD_REGISTERS (0xC0000000 | 0x0168) // ERRHRD, ERRgeneral
+#define NT_STATUS_DISK_RECALIBRATE_FAILED (0xC0000000 | 0x0169) // ERRHRD, ERRgeneral
+#define NT_STATUS_DISK_OPERATION_FAILED (0xC0000000 | 0x016a) // ERRHRD, ERRgeneral
+#define NT_STATUS_DISK_RESET_FAILED (0xC0000000 | 0x016b) // ERRHRD, ERRgeneral
+#define NT_STATUS_SHARED_IRQ_BUSY (0xC0000000 | 0x016c) // ERRHRD, ERRgeneral
+#define NT_STATUS_FT_ORPHANING (0xC0000000 | 0x016d) // ERRHRD, ERRgeneral
+#define NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT (0xC0000000 | 0x016e) // ERRHRD, ERRgeneral
+#define NT_STATUS_PARTITION_FAILURE (0xC0000000 | 0x0172) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_BLOCK_LENGTH (0xC0000000 | 0x0173) // ERRHRD, ERRgeneral
+#define NT_STATUS_DEVICE_NOT_PARTITIONED (0xC0000000 | 0x0174) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (0xC0000000 | 0x0175) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (0xC0000000 | 0x0176) // ERRHRD, ERRgeneral
+#define NT_STATUS_EOM_OVERFLOW (0xC0000000 | 0x0177) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_MEDIA (0xC0000000 | 0x0178) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_SUCH_MEMBER (0xC0000000 | 0x017a) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_MEMBER (0xC0000000 | 0x017b) // ERRHRD, ERRgeneral
+#define NT_STATUS_KEY_DELETED (0xC0000000 | 0x017c) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_LOG_SPACE (0xC0000000 | 0x017d) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_SIDS (0xC0000000 | 0x017e) // ERRHRD, ERRgeneral
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x017f) // ERRHRD, ERRgeneral
+#define NT_STATUS_KEY_HAS_CHILDREN (0xC0000000 | 0x0180) // ERRHRD, ERRgeneral
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE (0xC0000000 | 0x0181) // ERRHRD, ERRgeneral
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (0xC0000000 | 0x0182) // ERRDOS, 87
+#define NT_STATUS_DRIVER_INTERNAL_ERROR (0xC0000000 | 0x0183) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_DEVICE_STATE (0xC0000000 | 0x0184) // ERRDOS, 22
+#define NT_STATUS_IO_DEVICE_ERROR (0xC0000000 | 0x0185) // ERRHRD, ERRgeneral
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR (0xC0000000 | 0x0186) // ERRHRD, ERRgeneral
+#define NT_STATUS_BACKUP_CONTROLLER (0xC0000000 | 0x0187) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOG_FILE_FULL (0xC0000000 | 0x0188) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_LATE (0xC0000000 | 0x0189) // ERRDOS, 19
+#define NT_STATUS_NO_TRUST_LSA_SECRET (0xC0000000 | 0x018a) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (0xC0000000 | 0x018b) // ERRDOS, ERRnoaccess
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (0xC0000000 | 0x018c) // ERRDOS, ERRnoaccess
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (0xC0000000 | 0x018d) // ERRDOS, ERRnoaccess
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT (0xC0000000 | 0x018e) // ERRHRD, ERRgeneral
+#define NT_STATUS_EVENTLOG_CANT_START (0xC0000000 | 0x018f) // ERRHRD, ERRgeneral
+#define NT_STATUS_TRUST_FAILURE (0xC0000000 | 0x0190) // ERRDOS, ERRnoaccess
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (0xC0000000 | 0x0191) // ERRHRD, ERRgeneral
+#define NT_STATUS_NETLOGON_NOT_STARTED (0xC0000000 | 0x0192) // ERRDOS, ERRnetlogonNotStarted
+#define NT_STATUS_ACCOUNT_EXPIRED (0xC0000000 | 0x0193) // ERRSRV, ERRaccountexpired
+#define NT_STATUS_POSSIBLE_DEADLOCK (0xC0000000 | 0x0194) // ERRHRD, ERRgeneral
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (0xC0000000 | 0x0195) // ERRHRD, ERRgeneral
+#define NT_STATUS_REMOTE_SESSION_LIMIT (0xC0000000 | 0x0196) // ERRHRD, ERRgeneral
+#define NT_STATUS_EVENTLOG_FILE_CHANGED (0xC0000000 | 0x0197) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (0xC0000000 | 0x0198) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (0xC0000000 | 0x0199) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (0xC0000000 | 0x019a) // ERRDOS, ERRnoaccess
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (0xC0000000 | 0x019b) // ERRDOS, ERRnoaccess
+#define NT_STATUS_FS_DRIVER_REQUIRED (0xC0000000 | 0x019c) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_LOCK_RANGE (0xC0000000 | 0x01a1) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_USER_SESSION_KEY (0xC0000000 | 0x0202) // ERRHRD, ERRgeneral
+#define NT_STATUS_USER_SESSION_DELETED (0xC0000000 | 0x0203) // ERRDOS, 59
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (0xC0000000 | 0x0204) // ERRHRD, ERRgeneral
+#define NT_STATUS_INSUFF_SERVER_RESOURCES (0xC0000000 | 0x0205) // ERRDOS, ERRnoresource
+#define NT_STATUS_INVALID_BUFFER_SIZE (0xC0000000 | 0x0206) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT (0xC0000000 | 0x0207) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD (0xC0000000 | 0x0208) // ERRHRD, ERRgeneral
+#define NT_STATUS_TOO_MANY_ADDRESSES (0xC0000000 | 0x0209) // ERRDOS, 68
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS (0xC0000000 | 0x020a) // ERRDOS, 52
+#define NT_STATUS_ADDRESS_CLOSED (0xC0000000 | 0x020b) // ERRDOS, 64
+#define NT_STATUS_CONNECTION_DISCONNECTED (0xC0000000 | 0x020c) // ERRDOS, 64
+#define NT_STATUS_CONNECTION_RESET (0xC0000000 | 0x020d) // ERRDOS, 64
+#define NT_STATUS_TOO_MANY_NODES (0xC0000000 | 0x020e) // ERRDOS, 68
+#define NT_STATUS_TRANSACTION_ABORTED (0xC0000000 | 0x020f) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_TIMED_OUT (0xC0000000 | 0x0210) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_NO_RELEASE (0xC0000000 | 0x0211) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_NO_MATCH (0xC0000000 | 0x0212) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_RESPONDED (0xC0000000 | 0x0213) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_INVALID_ID (0xC0000000 | 0x0214) // ERRDOS, 59
+#define NT_STATUS_TRANSACTION_INVALID_TYPE (0xC0000000 | 0x0215) // ERRDOS, 59
+#define NT_STATUS_NOT_SERVER_SESSION (0xC0000000 | 0x0216) // ERRDOS, ERRunsup
+#define NT_STATUS_NOT_CLIENT_SESSION (0xC0000000 | 0x0217) // ERRDOS, ERRunsup
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (0xC0000000 | 0x0218) // ERRHRD, ERRgeneral
+#define NT_STATUS_DEBUG_ATTACH_FAILED (0xC0000000 | 0x0219) // ERRHRD, ERRgeneral
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (0xC0000000 | 0x021a) // ERRHRD, ERRgeneral
+#define NT_STATUS_DATA_NOT_ACCEPTED (0xC0000000 | 0x021b) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (0xC0000000 | 0x021c) // ERRHRD, ERRgeneral
+#define NT_STATUS_VDM_HARD_ERROR (0xC0000000 | 0x021d) // ERRHRD, ERRgeneral
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (0xC0000000 | 0x021e) // ERRHRD, ERRgeneral
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH (0xC0000000 | 0x021f) // ERRHRD, ERRgeneral
+#define NT_STATUS_MAPPED_ALIGNMENT (0xC0000000 | 0x0220) // ERRHRD, ERRgeneral
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (0xC0000000 | 0x0221) // ERRDOS, 193
+#define NT_STATUS_LOST_WRITEBEHIND_DATA (0xC0000000 | 0x0222) // ERRHRD, ERRgeneral
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (0xC0000000 | 0x0223) // ERRHRD, ERRgeneral
+#define NT_STATUS_PASSWORD_MUST_CHANGE (0xC0000000 | 0x0224) // ERRSRV, ERRpasswordExpired
+#define NT_STATUS_NOT_FOUND (0xC0000000 | 0x0225) // ERRHRD, ERRgeneral
+#define NT_STATUS_NOT_TINY_STREAM (0xC0000000 | 0x0226) // ERRHRD, ERRgeneral
+#define NT_STATUS_RECOVERY_FAILURE (0xC0000000 | 0x0227) // ERRHRD, ERRgeneral
+#define NT_STATUS_STACK_OVERFLOW_READ (0xC0000000 | 0x0228) // ERRHRD, ERRgeneral
+#define NT_STATUS_FAIL_CHECK (0xC0000000 | 0x0229) // ERRHRD, ERRgeneral
+#define NT_STATUS_DUPLICATE_OBJECTID (0xC0000000 | 0x022a) // ERRHRD, ERRgeneral
+#define NT_STATUS_OBJECTID_EXISTS (0xC0000000 | 0x022b) // ERRHRD, ERRgeneral
+#define NT_STATUS_CONVERT_TO_LARGE (0xC0000000 | 0x022c) // ERRHRD, ERRgeneral
+#define NT_STATUS_RETRY (0xC0000000 | 0x022d) // ERRHRD, ERRgeneral
+#define NT_STATUS_FOUND_OUT_OF_SCOPE (0xC0000000 | 0x022e) // ERRHRD, ERRgeneral
+#define NT_STATUS_ALLOCATE_BUCKET (0xC0000000 | 0x022f) // ERRHRD, ERRgeneral
+#define NT_STATUS_PROPSET_NOT_FOUND (0xC0000000 | 0x0230) // ERRHRD, ERRgeneral
+#define NT_STATUS_MARSHALL_OVERFLOW (0xC0000000 | 0x0231) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_VARIANT (0xC0000000 | 0x0232) // ERRHRD, ERRgeneral
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (0xC0000000 | 0x0233) // ERRHRD, ERRgeneral
+#define NT_STATUS_ACCOUNT_LOCKED_OUT (0xC0000000 | 0x0234) // ERRDOS, ERRnoaccess
+#define NT_STATUS_HANDLE_NOT_CLOSABLE (0xC0000000 | 0x0235) // ERRDOS, ERRbadfid
+#define NT_STATUS_CONNECTION_REFUSED (0xC0000000 | 0x0236) // ERRHRD, ERRgeneral
+#define NT_STATUS_GRACEFUL_DISCONNECT (0xC0000000 | 0x0237) // ERRHRD, ERRgeneral
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (0xC0000000 | 0x0238) // ERRHRD, ERRgeneral
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (0xC0000000 | 0x0239) // ERRHRD, ERRgeneral
+#define NT_STATUS_CONNECTION_INVALID (0xC0000000 | 0x023a) // ERRHRD, ERRgeneral
+#define NT_STATUS_CONNECTION_ACTIVE (0xC0000000 | 0x023b) // ERRHRD, ERRgeneral
+#define NT_STATUS_NETWORK_UNREACHABLE (0xC0000000 | 0x023c) // ERRHRD, ERRgeneral
+#define NT_STATUS_HOST_UNREACHABLE (0xC0000000 | 0x023d) // ERRHRD, ERRgeneral
+#define NT_STATUS_PROTOCOL_UNREACHABLE (0xC0000000 | 0x023e) // ERRHRD, ERRgeneral
+#define NT_STATUS_PORT_UNREACHABLE (0xC0000000 | 0x023f) // ERRHRD, ERRgeneral
+#define NT_STATUS_REQUEST_ABORTED (0xC0000000 | 0x0240) // ERRHRD, ERRgeneral
+#define NT_STATUS_CONNECTION_ABORTED (0xC0000000 | 0x0241) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_COMPRESSION_BUFFER (0xC0000000 | 0x0242) // ERRHRD, ERRgeneral
+#define NT_STATUS_USER_MAPPED_FILE (0xC0000000 | 0x0243) // ERRHRD, ERRgeneral
+#define NT_STATUS_AUDIT_FAILED (0xC0000000 | 0x0244) // ERRHRD, ERRgeneral
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (0xC0000000 | 0x0245) // ERRHRD, ERRgeneral
+#define NT_STATUS_CONNECTION_COUNT_LIMIT (0xC0000000 | 0x0246) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGIN_TIME_RESTRICTION (0xC0000000 | 0x0247) // ERRHRD, ERRgeneral
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (0xC0000000 | 0x0248) // ERRHRD, ERRgeneral
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH (0xC0000000 | 0x0249) // ERRDOS, 193
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO (0xC0000000 | 0x0250) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_DLL_ENTRYPOINT (0xC0000000 | 0x0251) // ERRHRD, ERRgeneral
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (0xC0000000 | 0x0252) // ERRHRD, ERRgeneral
+#define NT_STATUS_LPC_REPLY_LOST (0xC0000000 | 0x0253) // ERRHRD, ERRgeneral
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 (0xC0000000 | 0x0254) // ERRHRD, ERRgeneral
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 (0xC0000000 | 0x0255) // ERRHRD, ERRgeneral
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT (0xC0000000 | 0x0256) // ERRHRD, ERRgeneral
+#define NT_STATUS_PATH_NOT_COVERED (0xC0000000 | 0x0257) // ERRSRV, 3
+#define NT_STATUS_NO_CALLBACK_ACTIVE (0xC0000000 | 0x0258) // ERRHRD, ERRgeneral
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (0xC0000000 | 0x0259) // ERRHRD, ERRgeneral
+#define NT_STATUS_PWD_TOO_SHORT (0xC0000000 | 0x025a) // ERRHRD, ERRgeneral
+#define NT_STATUS_PWD_TOO_RECENT (0xC0000000 | 0x025b) // ERRHRD, ERRgeneral
+#define NT_STATUS_PWD_HISTORY_CONFLICT (0xC0000000 | 0x025c) // ERRHRD, ERRgeneral
+#define NT_STATUS_PLUGPLAY_NO_DEVICE (0xC0000000 | 0x025e) // ERRHRD, ERRgeneral
+#define NT_STATUS_UNSUPPORTED_COMPRESSION (0xC0000000 | 0x025f) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_HW_PROFILE (0xC0000000 | 0x0260) // ERRHRD, ERRgeneral
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (0xC0000000 | 0x0261) // ERRHRD, ERRgeneral
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (0xC0000000 | 0x0262) // ERRDOS, 182
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0263) // ERRDOS, 127
+#define NT_STATUS_RESOURCE_NOT_OWNED (0xC0000000 | 0x0264) // ERRDOS, 288
+#define NT_STATUS_TOO_MANY_LINKS (0xC0000000 | 0x0265) // ERRDOS, ErrTooManyLinks
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT (0xC0000000 | 0x0266) // ERRHRD, ERRgeneral
+#define NT_STATUS_FILE_IS_OFFLINE (0xC0000000 | 0x0267) // ERRHRD, ERRgeneral
+#define NT_STATUS_VOLUME_DISMOUNTED (0xC0000000 | 0x026e) // ERRDOS, 21
+#define NT_STATUS_NOT_A_REPARSE_POINT (0xC0000000 | 0x0275) // ERRHRD, ERRgeneral
+#define NT_STATUS_DIRECTORY_IS_A_REPARSE_POINT (0xC0000000 | 0x0281) // ERRDOS, 161
+#define NT_STATUS_ENCRYPTION_FAILED (0xC0000000 | 0x028a) // ERRDOS, ERRnoaccess
+#define NT_STATUS_DECRYPTION_FAILED (0xC0000000 | 0x028b) // ERRDOS, ERRnoaccess
+#define NT_STATUS_RANGE_NOT_FOUND (0xC0000000 | 0x028c) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_RECOVERY_POLICY (0xC0000000 | 0x028d) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NO_EFS (0xC0000000 | 0x028e) // ERRDOS, ERRnoaccess
+#define NT_STATUS_WRONG_EFS (0xC0000000 | 0x028f) // ERRDOS, ERRnoaccess
+#define NT_STATUS_NO_USER_KEYS (0xC0000000 | 0x0290) // ERRDOS, ERRnoaccess
+#define NT_STATUS_VOLUME_NOT_UPGRADED (0xC0000000 | 0x029c) // ERRDOS, ERRbadfunc
+#define NT_STATUS_NETWORK_SESSION_EXPIRED (0xC0000000 | 0x035c) // ERRHRD, ERRgeneral
+/* scheduler */
+#define NT_STATUS_NO_SUCH_JOB (0xC0000000 | 0xEDE) // ERRHRD, ERRgeneral
+#define NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP (0xC0000000 | 0x5D0000) // ERRHRD, ERRgeneral
+#define NT_STATUS_OS2_INVALID_LEVEL 0x007c0001 // ERRDOS, ERRunknownlevel
#endif /* _NTERR_H */
diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h
index 875de43b72de..be0365f08396 100644
--- a/fs/smb/client/ntlmssp.h
+++ b/fs/smb/client/ntlmssp.h
@@ -73,7 +73,7 @@ typedef struct _SECURITY_BUFFER {
__le16 Length;
__le16 MaximumLength;
__le32 BufferOffset; /* offset to buffer */
-} __attribute__((packed)) SECURITY_BUFFER;
+} __packed SECURITY_BUFFER;
typedef struct _NEGOTIATE_MESSAGE {
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
@@ -85,7 +85,7 @@ typedef struct _NEGOTIATE_MESSAGE {
do not set the version is present flag */
char DomainString[];
/* followed by WorkstationString */
-} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
+} __packed NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
#define NTLMSSP_REVISION_W2K3 0x0F
@@ -121,7 +121,7 @@ typedef struct _CHALLENGE_MESSAGE {
SECURITY_BUFFER TargetInfoArray;
/* SECURITY_BUFFER for version info not present since we
do not set the version is present flag */
-} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
+} __packed CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
typedef struct _AUTHENTICATE_MESSAGE {
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
@@ -136,22 +136,23 @@ typedef struct _AUTHENTICATE_MESSAGE {
struct ntlmssp_version Version;
/* SECURITY_BUFFER */
char UserString[];
-} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
+} __packed AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
/*
* Size of the session key (crypto key encrypted with the password
*/
-int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
+int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
+ struct cifs_ses *ses);
int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp);
int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
- struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const struct nls_table *nls_cp);
+ struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ const struct nls_table *nls_cp);
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
- struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const struct nls_table *nls_cp);
+ struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ const struct nls_table *nls_cp);
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 50f96259d9ad..be22bbc4a65a 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -9,10 +9,10 @@
*
*/
#include <linux/fs.h>
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/stat.h>
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
@@ -78,7 +78,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
- dentry = d_hash_and_lookup(parent, name);
+ dentry = try_lookup_noperm(name, parent);
if (!dentry) {
/*
* If we know that the inode will need to be revalidated
@@ -97,7 +97,7 @@ retry:
default:
break;
}
- } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
+ } else if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) {
reparse_need_reval = true;
}
@@ -121,7 +121,7 @@ retry:
* want to clobber the existing one with the one that
* the readdir code created.
*/
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM))
fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
/*
@@ -137,7 +137,7 @@ retry:
* reparse tag and ctime haven't changed.
*/
rc = 0;
- if (fattr->cf_cifsattrs & ATTR_REPARSE) {
+ if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) {
if (likely(reparse_inode_match(inode, fattr))) {
fattr->cf_mode = inode->i_mode;
fattr->cf_rdev = inode->i_rdev;
@@ -177,6 +177,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
struct cifs_open_info_data data = {
.reparse = { .tag = fattr->cf_cifstag, },
};
+ unsigned int sbflags;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
@@ -189,7 +190,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
* TODO: go through all documented reparse tags to see if we can
* reasonably map some of them to directories vs. files vs. symlinks
*/
- if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
+ if ((fattr->cf_cifsattrs & ATTR_REPARSE_POINT) &&
cifs_reparse_point_to_fattr(cifs_sb, fattr, &data))
goto out_reparse;
@@ -215,12 +216,12 @@ out_reparse:
* may look wrong since the inodes may not have timed out by the time
* "ls" does a stat() call on them.
*/
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID))
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
- fattr->cf_cifsattrs & ATTR_SYSTEM) {
+ if ((sbflags & CIFS_MOUNT_UNX_EMUL) &&
+ (fattr->cf_cifsattrs & ATTR_SYSTEM)) {
if (fattr->cf_eof == 0) {
fattr->cf_mode &= ~S_IFMT;
fattr->cf_mode |= S_IFIFO;
@@ -257,13 +258,13 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
- if (fattr->cf_cifsattrs & ATTR_REPARSE)
+ if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT)
fattr->cf_cifstag = le32_to_cpu(info->ReparseTag);
/* The Mode field in the response can now include the file type as well */
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode),
fattr->cf_cifsattrs & ATTR_DIRECTORY);
- fattr->cf_dtype = S_DT(le32_to_cpu(info->Mode));
+ fattr->cf_dtype = S_DT(fattr->cf_mode);
switch (fattr->cf_mode & S_IFMT) {
case S_IFLNK:
@@ -315,7 +316,7 @@ static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr,
__dir_info_to_fattr(fattr, info);
/* See MS-FSCC 2.4.14, 2.4.19 */
- if (fattr->cf_cifsattrs & ATTR_REPARSE)
+ if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT)
fattr->cf_cifstag = le32_to_cpu(di->EaSize);
cifs_fill_common_info(fattr, cifs_sb);
}
@@ -345,20 +346,21 @@ static int
_initiate_cifs_search(const unsigned int xid, struct file *file,
const char *full_path)
{
- __u16 search_flags;
- int rc = 0;
- struct cifsFileInfo *cifsFile;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
struct tcon_link *tlink = NULL;
- struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
+ struct cifsFileInfo *cifsFile;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ __u16 search_flags;
+ int rc = 0;
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+ cifsFile = kzalloc_obj(struct cifsFileInfo);
if (cifsFile == NULL) {
rc = -ENOMEM;
goto error_exit;
@@ -385,6 +387,7 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,
cifs_dbg(FYI, "Full path: %s start at: %lld\n", full_path, file->f_pos);
ffirst_retry:
+ sbflags = cifs_sb_flags(cifs_sb);
/* test for Unix extensions */
/* but now check for them on the share/mount not on the SMB session */
/* if (cap_unix(tcon->ses) { */
@@ -395,7 +398,7 @@ ffirst_retry:
else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ } else if (sbflags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
} else /* not srvinos - BB fixme add check for backlevel? */ {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
@@ -411,8 +414,7 @@ ffirst_retry:
if (rc == 0) {
cifsFile->invalidHandle = false;
- } else if ((rc == -EOPNOTSUPP) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ } else if (rc == -EOPNOTSUPP && (sbflags & CIFS_MOUNT_SERVER_INUM)) {
cifs_autodisable_serverino(cifs_sb);
goto ffirst_retry;
}
@@ -547,7 +549,7 @@ static void cifs_fill_dirent_full(struct cifs_dirent *de,
}
static void cifs_fill_dirent_search(struct cifs_dirent *de,
- const SEARCH_ID_FULL_DIR_INFO *info)
+ const FILE_ID_FULL_DIR_INFO *info)
{
de->name = &info->FileName[0];
de->namelen = le32_to_cpu(info->FileNameLength);
@@ -690,7 +692,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
loff_t first_entry_in_buffer;
loff_t index_to_find = pos;
struct cifsFileInfo *cfile = file->private_data;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
struct TCP_Server_Info *server = tcon->ses->server;
/* check if index in the buffer */
@@ -733,7 +735,10 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
else
cifs_buf_release(cfile->srch_inf.
ntwrk_buf_start);
+ /* Reset all pointers to the network buffer to prevent stale references */
cfile->srch_inf.ntwrk_buf_start = NULL;
+ cfile->srch_inf.srch_entries_start = NULL;
+ cfile->srch_inf.last_entry = NULL;
}
rc = initiate_cifs_search(xid, file, full_path);
if (rc) {
@@ -756,11 +761,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
search_flags,
&cfile->srch_inf);
+ if (rc)
+ return -ENOENT;
/* FindFirst/Next set last_entry to NULL on malformed reply */
if (cfile->srch_inf.last_entry)
cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
- if (rc)
- return -ENOENT;
}
if (index_to_find < cfile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */
@@ -771,7 +776,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
if (cfile->srch_inf.ntwrk_buf_start == NULL) {
cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
}
end_of_smb = cfile->srch_inf.ntwrk_buf_start +
@@ -847,9 +852,9 @@ static bool emit_cached_dirents(struct cached_dirents *cde,
}
static void update_cached_dirents_count(struct cached_dirents *cde,
- struct dir_context *ctx)
+ struct file *file)
{
- if (cde->ctx != ctx)
+ if (cde->file != file)
return;
if (cde->is_valid || cde->is_failed)
return;
@@ -858,9 +863,9 @@ static void update_cached_dirents_count(struct cached_dirents *cde,
}
static void finished_cached_dirents_count(struct cached_dirents *cde,
- struct dir_context *ctx)
+ struct dir_context *ctx, struct file *file)
{
- if (cde->ctx != ctx)
+ if (cde->file != file)
return;
if (cde->is_valid || cde->is_failed)
return;
@@ -870,46 +875,52 @@ static void finished_cached_dirents_count(struct cached_dirents *cde,
cde->is_valid = 1;
}
-static void add_cached_dirent(struct cached_dirents *cde,
- struct dir_context *ctx,
- const char *name, int namelen,
- struct cifs_fattr *fattr)
+static bool add_cached_dirent(struct cached_dirents *cde,
+ struct dir_context *ctx, const char *name,
+ int namelen, struct cifs_fattr *fattr,
+ struct file *file)
{
struct cached_dirent *de;
- if (cde->ctx != ctx)
- return;
+ if (cde->file != file)
+ return false;
if (cde->is_valid || cde->is_failed)
- return;
+ return false;
if (ctx->pos != cde->pos) {
cde->is_failed = 1;
- return;
+ return false;
}
- de = kzalloc(sizeof(*de), GFP_ATOMIC);
+ de = kzalloc_obj(*de, GFP_ATOMIC);
if (de == NULL) {
cde->is_failed = 1;
- return;
+ return false;
}
de->namelen = namelen;
de->name = kstrndup(name, namelen, GFP_ATOMIC);
if (de->name == NULL) {
kfree(de);
cde->is_failed = 1;
- return;
+ return false;
}
de->pos = ctx->pos;
memcpy(&de->fattr, fattr, sizeof(struct cifs_fattr));
list_add_tail(&de->entry, &cde->entries);
+ /* update accounting */
+ cde->entries_count++;
+ cde->bytes_used += sizeof(*de) + (size_t)namelen + 1;
+ return true;
}
static bool cifs_dir_emit(struct dir_context *ctx,
const char *name, int namelen,
struct cifs_fattr *fattr,
- struct cached_fid *cfid)
+ struct cached_fid *cfid,
+ struct file *file)
{
- bool rc;
+ size_t delta_bytes = 0;
+ bool rc, added = false;
ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
rc = dir_emit(ctx, name, namelen, ino, fattr->cf_dtype);
@@ -917,10 +928,20 @@ static bool cifs_dir_emit(struct dir_context *ctx,
return rc;
if (cfid) {
+ /* Cost of this entry */
+ delta_bytes = sizeof(struct cached_dirent) + (size_t)namelen + 1;
+
mutex_lock(&cfid->dirents.de_mutex);
- add_cached_dirent(&cfid->dirents, ctx, name, namelen,
- fattr);
+ added = add_cached_dirent(&cfid->dirents, ctx, name, namelen,
+ fattr, file);
mutex_unlock(&cfid->dirents.de_mutex);
+
+ if (added) {
+ /* per-tcon then global for consistency with free path */
+ atomic64_add((long long)delta_bytes, &cfid->cfids->total_dirents_bytes);
+ atomic_long_inc(&cfid->cfids->total_dirents_entries);
+ atomic64_add((long long)delta_bytes, &cifs_dircache_bytes_used);
+ }
}
return rc;
@@ -936,6 +957,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_dirent de = { NULL, };
struct cifs_fattr fattr;
+ unsigned int sbflags;
struct qstr name;
int rc = 0;
@@ -1000,15 +1022,15 @@ static int cifs_filldir(char *find_entry, struct file *file,
break;
}
- if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (de.ino && (sbflags & CIFS_MOUNT_SERVER_INUM)) {
fattr.cf_uniqueid = de.ino;
} else {
fattr.cf_uniqueid = iunique(sb, ROOT_I);
cifs_autodisable_serverino(cifs_sb);
}
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
- couldbe_mf_symlink(&fattr))
+ if ((sbflags & CIFS_MOUNT_MF_SYMLINKS) && couldbe_mf_symlink(&fattr))
/*
* trying to get the type and mode can be slow,
* so just call those regular files for now, and mark
@@ -1019,7 +1041,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
cifs_prime_dcache(file_dentry(file), &name, &fattr);
return !cifs_dir_emit(ctx, name.name, name.len,
- &fattr, cfid);
+ &fattr, cfid, file);
}
@@ -1039,7 +1061,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
const char *full_path;
void *page = alloc_dentry_path();
struct cached_fid *cfid = NULL;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
xid = get_xid();
@@ -1070,8 +1092,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
* we need to initialize scanning and storing the
* directory content.
*/
- if (ctx->pos == 0 && cfid->dirents.ctx == NULL) {
- cfid->dirents.ctx = ctx;
+ if (ctx->pos == 0 && cfid->dirents.file == NULL) {
+ cfid->dirents.file = file;
cfid->dirents.pos = 2;
}
/*
@@ -1139,7 +1161,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
} else {
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
- finished_cached_dirents_count(&cfid->dirents, ctx);
+ finished_cached_dirents_count(&cfid->dirents, ctx, file);
mutex_unlock(&cfid->dirents.de_mutex);
}
cifs_dbg(FYI, "Could not find entry\n");
@@ -1180,7 +1202,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
ctx->pos++;
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
- update_cached_dirents_count(&cfid->dirents, ctx);
+ update_cached_dirents_count(&cfid->dirents, file);
mutex_unlock(&cfid->dirents.de_mutex);
}
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index bb25e77c5540..cd1e1eaee67a 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -34,11 +34,11 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
const char *symname,
bool *directory);
-int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
+int create_reparse_symlink(const unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, const char *symname)
{
- switch (get_cifs_symlink_type(CIFS_SB(inode->i_sb))) {
+ switch (cifs_symlink_type(CIFS_SB(inode->i_sb))) {
case CIFS_SYMLINK_TYPE_NATIVE:
return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
case CIFS_SYMLINK_TYPE_NFS:
@@ -55,16 +55,18 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
const char *full_path, const char *symname)
{
struct reparse_symlink_data_buffer *buf = NULL;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ const char *symroot = cifs_sb->ctx->symlinkroot;
struct cifs_open_info_data data = {};
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ char sep = CIFS_DIR_SEP(cifs_sb);
+ char *symlink_target = NULL;
+ u16 len, plen, poff, slen;
+ unsigned int sbflags;
+ __le16 *path = NULL;
struct inode *new;
+ char *sym = NULL;
struct kvec iov;
- __le16 *path = NULL;
bool directory;
- char *symlink_target = NULL;
- char *sym = NULL;
- char sep = CIFS_DIR_SEP(cifs_sb);
- u16 len, plen, poff, slen;
int rc = 0;
if (strlen(symname) > REPARSE_SYM_PATH_MAX)
@@ -82,7 +84,8 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
.symlink_target = symlink_target,
};
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symroot && symname[0] == '/') {
/*
* This is a request to create an absolute symlink on the server
* which does not support POSIX paths, and expects symlink in
@@ -92,7 +95,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
* ensure compatibility of this symlink stored in absolute form
* on the SMB server.
*/
- if (!strstarts(symname, cifs_sb->ctx->symlinkroot)) {
+ if (!strstarts(symname, symroot)) {
/*
* If the absolute Linux symlink target path is not
* inside "symlinkroot" location then there is no way
@@ -101,12 +104,12 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
cifs_dbg(VFS,
"absolute symlink '%s' cannot be converted to NT format "
"because it is outside of symlinkroot='%s'\n",
- symname, cifs_sb->ctx->symlinkroot);
+ symname, symroot);
rc = -EINVAL;
goto out;
}
- len = strlen(cifs_sb->ctx->symlinkroot);
- if (cifs_sb->ctx->symlinkroot[len-1] != '/')
+ len = strlen(symroot);
+ if (symroot[len - 1] != '/')
len++;
if (symname[len] >= 'a' && symname[len] <= 'z' &&
(symname[len+1] == '/' || symname[len+1] == '\0')) {
@@ -162,7 +165,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
* mask these characters in NT object prefix by '_' and then change
* them back.
*/
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/')
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/')
sym[0] = sym[1] = sym[2] = sym[5] = '_';
path = cifs_convert_path_to_utf16(sym, cifs_sb);
@@ -171,7 +174,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
goto out;
}
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
sym[0] = '\\';
sym[1] = sym[2] = '?';
sym[5] = ':';
@@ -195,7 +198,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
slen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX);
poff = 0;
plen = slen;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
/*
* For absolute NT symlinks skip leading "\\??\\" in PrintName as
* PrintName is user visible location in DOS/Win32 format (not in NT format).
@@ -225,7 +228,8 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
iov.iov_base = buf;
iov.iov_len = len;
- new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
+ new = tcon->ses->server->ops->create_reparse_inode(
+ &data, inode->i_sb, xid,
tcon, full_path, directory,
&iov, NULL);
if (!IS_ERR(new))
@@ -275,7 +279,7 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
}
/*
- * For absolute symlinks it is not possible to determinate
+ * For absolute symlinks it is not possible to determine
* if it should point to directory or file.
*/
if (symname[0] == '/') {
@@ -397,7 +401,8 @@ static int create_native_socket(const unsigned int xid, struct inode *inode,
struct inode *new;
int rc = 0;
- new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
+ new = tcon->ses->server->ops->create_reparse_inode(
+ &data, inode->i_sb, xid,
tcon, full_path, false, &iov, NULL);
if (!IS_ERR(new))
d_instantiate(dentry, new);
@@ -490,7 +495,8 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
.symlink_target = kstrdup(symname, GFP_KERNEL),
};
- new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
+ new = tcon->ses->server->ops->create_reparse_inode(
+ &data, inode->i_sb, xid,
tcon, full_path, false, &iov, NULL);
if (!IS_ERR(new))
d_instantiate(dentry, new);
@@ -683,7 +689,8 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
memcpy(data.wsl.eas, &cc->ea, len);
data.wsl.eas_len = len;
- new = smb2_get_reparse_inode(&data, inode->i_sb,
+ new = tcon->ses->server->ops->create_reparse_inode(
+ &data, inode->i_sb,
xid, tcon, full_path, false,
&reparse_iov, &xattr_iov);
if (!IS_ERR(new))
@@ -696,7 +703,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
return rc;
}
-int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
+int mknod_reparse(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, umode_t mode, dev_t dev)
{
@@ -726,7 +733,8 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
len = le16_to_cpu(buf->ReparseDataLength);
if (len < sizeof(buf->InodeType)) {
cifs_dbg(VFS, "srv returned malformed nfs buffer\n");
- return -EIO;
+ return smb_EIO2(smb_eio_trace_reparse_nfs_too_short,
+ len, sizeof(buf->InodeType));
}
len -= sizeof(buf->InodeType);
@@ -735,7 +743,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
case NFS_SPECFILE_LNK:
if (len == 0 || (len % 2)) {
cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
- return -EIO;
+ return smb_EIO1(smb_eio_trace_reparse_nfs_symbuf, len);
}
/*
* Check that buffer does not contain UTF-16 null codepoint
@@ -743,7 +751,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
*/
if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
- return -EIO;
+ return smb_EIO1(smb_eio_trace_reparse_nfs_nul, len);
}
data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
len, true,
@@ -758,7 +766,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
/* DataBuffer for block and char devices contains two 32-bit numbers */
if (len != 8) {
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
- return -EIO;
+ return smb_EIO1(smb_eio_trace_reparse_nfs_dev, len);
}
break;
case NFS_SPECFILE_FIFO:
@@ -766,7 +774,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
/* DataBuffer for fifos and sockets is empty */
if (len != 0) {
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
- return -EIO;
+ return smb_EIO1(smb_eio_trace_reparse_nfs_sockfifo, len);
}
break;
default:
@@ -782,6 +790,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
const char *full_path,
struct cifs_sb_info *cifs_sb)
{
+ const char *symroot = cifs_sb->ctx->symlinkroot;
char sep = CIFS_DIR_SEP(cifs_sb);
char *linux_target = NULL;
char *smb_target = NULL;
@@ -789,13 +798,13 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
int abs_path_len;
char *abs_path;
int levels;
- int rc;
+ int rc, ulen;
int i;
/* Check that length it valid */
if (!len || (len % 2)) {
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_reparse_native_nul, len);
goto out;
}
@@ -803,9 +812,10 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
* Check that buffer does not contain UTF-16 null codepoint
* because Linux cannot process symlink with null byte.
*/
- if (UniStrnlen((wchar_t *)buf, len/2) != len/2) {
+ ulen = UniStrnlen((wchar_t *)buf, len/2);
+ if (ulen != len/2) {
cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_reparse_native_nul, ulen, len);
goto out;
}
@@ -815,7 +825,8 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
goto out;
}
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && !relative) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS) &&
+ symroot && !relative) {
/*
* This is an absolute symlink from the server which does not
* support POSIX paths, so the symlink is in NT-style path.
@@ -875,15 +886,8 @@ globalroot:
abs_path += sizeof("\\DosDevices\\")-1;
else if (strstarts(abs_path, "\\GLOBAL??\\"))
abs_path += sizeof("\\GLOBAL??\\")-1;
- else {
- /* Unhandled absolute symlink, points outside of DOS/Win32 */
- cifs_dbg(VFS,
- "absolute symlink '%s' cannot be converted from NT format "
- "because points to unknown target\n",
- smb_target);
- rc = -EIO;
- goto out;
- }
+ else
+ goto out_unhandled_target;
/* Sometimes path separator after \?? is double backslash */
if (abs_path[0] == '\\')
@@ -910,25 +914,19 @@ globalroot:
abs_path++;
abs_path[0] = drive_letter;
} else {
- /* Unhandled absolute symlink. Report an error. */
- cifs_dbg(VFS,
- "absolute symlink '%s' cannot be converted from NT format "
- "because points to unknown target\n",
- smb_target);
- rc = -EIO;
- goto out;
+ goto out_unhandled_target;
}
abs_path_len = strlen(abs_path)+1;
- symlinkroot_len = strlen(cifs_sb->ctx->symlinkroot);
- if (cifs_sb->ctx->symlinkroot[symlinkroot_len-1] == '/')
+ symlinkroot_len = strlen(symroot);
+ if (symroot[symlinkroot_len - 1] == '/')
symlinkroot_len--;
linux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
if (!linux_target) {
rc = -ENOMEM;
goto out;
}
- memcpy(linux_target, cifs_sb->ctx->symlinkroot, symlinkroot_len);
+ memcpy(linux_target, symroot, symlinkroot_len);
linux_target[symlinkroot_len] = '/';
memcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
} else if (smb_target[0] == sep && relative) {
@@ -966,6 +964,7 @@ globalroot:
* These paths have same format as Linux symlinks, so no
* conversion is needed.
*/
+out_unhandled_target:
linux_target = smb_target;
smb_target = NULL;
}
@@ -1000,7 +999,8 @@ static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
len = le16_to_cpu(sym->SubstituteNameLength);
if (offs + 20 > plen || offs + len + 20 > plen) {
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
- return -EIO;
+ return smb_EIO2(smb_eio_trace_reparse_native_sym_len,
+ offs << 16 | len, plen);
}
return smb2_parse_native_symlink(&data->symlink_target,
@@ -1023,13 +1023,16 @@ static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf
if (len <= data_offset) {
cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n");
- return -EIO;
+ return smb_EIO2(smb_eio_trace_reparse_wsl_symbuf,
+ len, data_offset);
}
/* MS-FSCC 2.1.2.7 defines layout of the Target field only for Version 2. */
- if (le32_to_cpu(buf->Version) != 2) {
- cifs_dbg(VFS, "srv returned unsupported wsl symlink version %u\n", le32_to_cpu(buf->Version));
- return -EIO;
+ u32 version = le32_to_cpu(buf->Version);
+
+ if (version != 2) {
+ cifs_dbg(VFS, "srv returned unsupported wsl symlink version %u\n", version);
+ return smb_EIO1(smb_eio_trace_reparse_wsl_ver, version);
}
/* Target for Version 2 is in UTF-8 but without trailing null-term byte */
@@ -1038,9 +1041,12 @@ static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf
* Check that buffer does not contain null byte
* because Linux cannot process symlink with null byte.
*/
- if (strnlen(buf->Target, symname_utf8_len) != symname_utf8_len) {
+ size_t ulen = strnlen(buf->Target, symname_utf8_len);
+
+ if (ulen != symname_utf8_len) {
cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n");
- return -EIO;
+ return smb_EIO2(smb_eio_trace_reparse_wsl_ver,
+ ulen, symname_utf8_len);
}
symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
if (!symname_utf16)
@@ -1087,13 +1093,17 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_AF_UNIX:
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_LX_CHR:
- case IO_REPARSE_TAG_LX_BLK:
- if (le16_to_cpu(buf->ReparseDataLength) != 0) {
+ case IO_REPARSE_TAG_LX_BLK: {
+ u16 dlen = le16_to_cpu(buf->ReparseDataLength);
+
+ if (dlen != 0) {
+ u32 rtag = le32_to_cpu(buf->ReparseTag);
cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
- le32_to_cpu(buf->ReparseTag));
- return -EIO;
+ rtag);
+ return smb_EIO2(smb_eio_trace_reparse_data_len, dlen, rtag);
}
return 0;
+ }
default:
return -EOPNOTSUPP;
}
@@ -1172,7 +1182,6 @@ out:
if (!have_xattr_dev && (tag == IO_REPARSE_TAG_LX_CHR || tag == IO_REPARSE_TAG_LX_BLK))
return false;
- fattr->cf_dtype = S_DT(fattr->cf_mode);
return true;
}
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index 08de853b36a8..0164dc47bdfd 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -11,6 +11,7 @@
#include <linux/uidgid.h>
#include "fs_context.h"
#include "cifsglob.h"
+#include "../common/smbfsctl.h"
#define REPARSE_SYM_PATH_MAX 4060
@@ -32,7 +33,7 @@ static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
{
u32 uid = le32_to_cpu(*(__le32 *)ptr);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_UID)
return cifs_sb->ctx->linux_uid;
return make_kuid(current_user_ns(), uid);
}
@@ -42,7 +43,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
{
u32 gid = le32_to_cpu(*(__le32 *)ptr);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_GID)
return cifs_sb->ctx->linux_gid;
return make_kgid(current_user_ns(), gid);
}
@@ -93,7 +94,7 @@ static inline bool reparse_inode_match(struct inode *inode,
if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL &&
cinode->reparse_tag != fattr->cf_cifstag)
return false;
- return (cinode->cifsAttrs & ATTR_REPARSE) &&
+ return (cinode->cifsAttrs & ATTR_REPARSE_POINT) &&
timespec64_equal(&ctime, &fattr->cf_ctime);
}
@@ -107,7 +108,7 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
attrs = le32_to_cpu(fi->DosAttributes);
if (data->reparse_point) {
- attrs |= ATTR_REPARSE;
+ attrs |= ATTR_REPARSE_POINT;
fi->DosAttributes = cpu_to_le32(attrs);
}
@@ -116,12 +117,12 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
attrs = le32_to_cpu(fi->Attributes);
if (data->reparse_point) {
- attrs |= ATTR_REPARSE;
+ attrs |= ATTR_REPARSE_POINT;
fi->Attributes = cpu_to_le32(attrs);
}
}
- ret = attrs & ATTR_REPARSE;
+ ret = attrs & ATTR_REPARSE_POINT;
return ret;
}
@@ -129,12 +130,13 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr,
struct cifs_open_info_data *data);
-int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
- struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, const char *symname);
-int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
- struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev);
-struct reparse_data_buffer *smb2_get_reparse_point_buffer(const struct kvec *rsp_iov, u32 *len);
+int create_reparse_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname);
+int mknod_reparse(unsigned int xid, struct inode *inode, struct dentry *dentry,
+ struct cifs_tcon *tcon, const char *full_path, umode_t mode,
+ dev_t dev);
+struct reparse_data_buffer *smb2_get_reparse_point_buffer(const struct kvec *rsp_iov,
+ u32 *plen);
#endif /* _CIFS_REPARSE_H */
diff --git a/fs/smb/client/rfc1002pdu.h b/fs/smb/client/rfc1002pdu.h
index ac82c2f3a4a2..f5b143088b90 100644
--- a/fs/smb/client/rfc1002pdu.h
+++ b/fs/smb/client/rfc1002pdu.h
@@ -33,17 +33,17 @@ struct rfc1002_session_packet {
__u8 calling_len;
__u8 calling_name[32];
__u8 scope2; /* null */
- } __attribute__((packed)) session_req;
+ } __packed session_req;
struct {
__be32 retarget_ip_addr;
__be16 port;
- } __attribute__((packed)) retarget_resp;
+ } __packed retarget_resp;
__u8 neg_ses_resp_error_code;
/* POSITIVE_SESSION_RESPONSE packet does not include trailer.
SESSION_KEEP_ALIVE packet also does not include a trailer.
Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
- } __attribute__((packed)) trailer;
-} __attribute__((packed));
+ } __packed trailer;
+} __packed;
/* Negative Session Response error codes */
#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index b3fa9ee26912..de2012cc9cf3 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -8,7 +8,6 @@
*
*/
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
@@ -265,12 +264,16 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
}
/*
- * called when multichannel is disabled by the server.
- * this always gets called from smb2_reconnect
- * and cannot get called in parallel threads.
+ * cifs_decrease_secondary_channels - Reduce the number of active secondary channels
+ * @ses: pointer to the CIFS session structure
+ * @disable_mchan: if true, reduce to a single channel; if false, reduce to chan_max
+ *
+ * This function disables and cleans up extra secondary channels for a CIFS session.
+ * If called during reconfiguration, it reduces the channel count to the new maximum (chan_max).
+ * Otherwise, it disables all but the primary channel.
*/
void
-cifs_disable_secondary_channels(struct cifs_ses *ses)
+cifs_decrease_secondary_channels(struct cifs_ses *ses, bool disable_mchan)
{
int i, chan_count;
struct TCP_Server_Info *server;
@@ -281,12 +284,16 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
if (chan_count == 1)
goto done;
- ses->chan_count = 1;
-
- /* for all secondary channels reset the need reconnect bit */
- ses->chans_need_reconnect &= 1;
+ /* Update the chan_count to the new maximum */
+ if (disable_mchan) {
+ cifs_dbg(FYI, "server does not support multichannel anymore.\n");
+ ses->chan_count = 1;
+ } else {
+ ses->chan_count = ses->chan_max;
+ }
- for (i = 1; i < chan_count; i++) {
+ /* Disable all secondary channels beyond the new chan_count */
+ for (i = ses->chan_count ; i < chan_count; i++) {
iface = ses->chans[i].iface;
server = ses->chans[i].server;
@@ -318,6 +325,15 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
spin_lock(&ses->chan_lock);
}
+ /* For extra secondary channels, reset the need reconnect bit */
+ if (ses->chan_count == 1) {
+ cifs_dbg(VFS, "Disable all secondary channels\n");
+ ses->chans_need_reconnect &= 1;
+ } else {
+ cifs_dbg(VFS, "Disable extra secondary channels\n");
+ ses->chans_need_reconnect &= ((1UL << ses->chan_max) - 1);
+ }
+
done:
spin_unlock(&ses->chan_lock);
}
@@ -332,6 +348,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
struct cifs_server_iface *old_iface = NULL;
struct cifs_server_iface *last_iface = NULL;
struct sockaddr_storage ss;
+ int retry = 0;
spin_lock(&ses->chan_lock);
chan_index = cifs_ses_get_chan_index(ses, server);
@@ -360,6 +377,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
return;
}
+try_again:
last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
iface_head);
iface_min_speed = last_iface->speed;
@@ -397,6 +415,13 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
}
if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
+ list_for_each_entry(iface, &ses->iface_list, iface_head)
+ iface->weight_fulfilled = 0;
+
+ /* see if it can be satisfied in second attempt */
+ if (!retry++)
+ goto try_again;
+
iface = NULL;
cifs_dbg(FYI, "unable to find a suitable iface\n");
}
@@ -445,6 +470,10 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
ses->chans[chan_index].iface = iface;
spin_unlock(&ses->chan_lock);
+
+ spin_lock(&server->srv_lock);
+ memcpy(&server->dstaddr, &iface->sockaddr, sizeof(server->dstaddr));
+ spin_unlock(&server->srv_lock);
}
static int
@@ -481,7 +510,7 @@ cifs_ses_add_channel(struct cifs_ses *ses,
* the session and server without caring about memory
* management.
*/
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx) {
rc = -ENOMEM;
goto out_free_xid;
@@ -494,8 +523,7 @@ cifs_ses_add_channel(struct cifs_ses *ses,
ctx->domainauto = ses->domainAuto;
ctx->domainname = ses->domainName;
- /* no hostname for extra channels */
- ctx->server_hostname = "";
+ ctx->server_hostname = ses->server->hostname;
ctx->username = ses->user_name;
ctx->password = ses->password;
@@ -567,17 +595,6 @@ cifs_ses_add_channel(struct cifs_ses *ses,
spin_unlock(&ses->chan_lock);
mutex_lock(&ses->session_mutex);
- /*
- * We need to allocate the server crypto now as we will need
- * to sign packets before we generate the channel signing key
- * (we sign with the session key)
- */
- rc = smb311_crypto_shash_allocate(chan->server);
- if (rc) {
- cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
- mutex_unlock(&ses->session_mutex);
- goto out;
- }
rc = cifs_negotiate_protocol(xid, ses, chan->server);
if (!rc)
@@ -610,278 +627,6 @@ out_free_xid:
return rc;
}
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- SESSION_SETUP_ANDX *pSMB)
-{
- __u32 capabilities = 0;
-
- /* init fields common to all four types of SessSetup */
- /* Note that offsets for first seven fields in req struct are same */
- /* in CIFS Specs so does not matter which of 3 forms of struct */
- /* that we use in next few lines */
- /* Note that header is initialized to zero in header_assemble */
- pSMB->req.AndXCommand = 0xFF;
- pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32,
- CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
- USHRT_MAX));
- pSMB->req.MaxMpxCount = cpu_to_le16(server->maxReq);
- pSMB->req.VcNumber = cpu_to_le16(1);
-
- /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
-
- /* BB verify whether signing required on neg or just auth frame (and NTLM case) */
-
- capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
- CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
-
- if (server->sign)
- pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
- if (ses->capabilities & CAP_UNICODE) {
- pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
- capabilities |= CAP_UNICODE;
- }
- if (ses->capabilities & CAP_STATUS32) {
- pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
- capabilities |= CAP_STATUS32;
- }
- if (ses->capabilities & CAP_DFS) {
- pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
- capabilities |= CAP_DFS;
- }
- if (ses->capabilities & CAP_UNIX)
- capabilities |= CAP_UNIX;
-
- return capabilities;
-}
-
-static void
-unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
- int bytes_ret = 0;
-
- /* Copy OS version */
- bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Linux version ", 32,
- nls_cp);
- bcc_ptr += 2 * bytes_ret;
- bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, init_utsname()->release,
- 32, nls_cp);
- bcc_ptr += 2 * bytes_ret;
- bcc_ptr += 2; /* trailing null */
-
- bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
- 32, nls_cp);
- bcc_ptr += 2 * bytes_ret;
- bcc_ptr += 2; /* trailing null */
-
- *pbcc_area = bcc_ptr;
-}
-
-static void
-ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
-
- strcpy(bcc_ptr, "Linux version ");
- bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, init_utsname()->release);
- bcc_ptr += strlen(init_utsname()->release) + 1;
-
- strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
- bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-
- *pbcc_area = bcc_ptr;
-}
-
-static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
- int bytes_ret = 0;
-
- /* copy domain */
- if (ses->domainName == NULL) {
- /*
- * Sending null domain better than using a bogus domain name (as
- * we did briefly in 2.6.18) since server will use its default
- */
- *bcc_ptr = 0;
- *(bcc_ptr+1) = 0;
- bytes_ret = 0;
- } else
- bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
- CIFS_MAX_DOMAINNAME_LEN, nls_cp);
- bcc_ptr += 2 * bytes_ret;
- bcc_ptr += 2; /* account for null terminator */
-
- *pbcc_area = bcc_ptr;
-}
-
-static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
- int len;
-
- /* copy domain */
- if (ses->domainName != NULL) {
- len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
- if (WARN_ON_ONCE(len < 0))
- len = CIFS_MAX_DOMAINNAME_LEN - 1;
- bcc_ptr += len;
- } /* else we send a null domain name so server will default to its own domain */
- *bcc_ptr = 0;
- bcc_ptr++;
-
- *pbcc_area = bcc_ptr;
-}
-
-static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
- int bytes_ret = 0;
-
- /* BB FIXME add check that strings less than 335 or will need to send as arrays */
-
- /* copy user */
- if (ses->user_name == NULL) {
- /* null user mount */
- *bcc_ptr = 0;
- *(bcc_ptr+1) = 0;
- } else {
- bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name,
- CIFS_MAX_USERNAME_LEN, nls_cp);
- }
- bcc_ptr += 2 * bytes_ret;
- bcc_ptr += 2; /* account for null termination */
-
- unicode_domain_string(&bcc_ptr, ses, nls_cp);
- unicode_oslm_strings(&bcc_ptr, nls_cp);
-
- *pbcc_area = bcc_ptr;
-}
-
-static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- char *bcc_ptr = *pbcc_area;
- int len;
-
- /* copy user */
- /* BB what about null user mounts - check that we do this BB */
- /* copy user */
- if (ses->user_name != NULL) {
- len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
- if (WARN_ON_ONCE(len < 0))
- len = CIFS_MAX_USERNAME_LEN - 1;
- bcc_ptr += len;
- }
- /* else null user mount */
- *bcc_ptr = 0;
- bcc_ptr++; /* account for null termination */
-
- /* BB check for overflow here */
-
- ascii_domain_string(&bcc_ptr, ses, nls_cp);
- ascii_oslm_strings(&bcc_ptr, nls_cp);
-
- *pbcc_area = bcc_ptr;
-}
-
-static void
-decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- int len;
- char *data = *pbcc_area;
-
- cifs_dbg(FYI, "bleft %d\n", bleft);
-
- kfree(ses->serverOS);
- ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
- cifs_dbg(FYI, "serverOS=%s\n", ses->serverOS);
- len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
- data += len;
- bleft -= len;
- if (bleft <= 0)
- return;
-
- kfree(ses->serverNOS);
- ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
- cifs_dbg(FYI, "serverNOS=%s\n", ses->serverNOS);
- len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
- data += len;
- bleft -= len;
- if (bleft <= 0)
- return;
-
- kfree(ses->serverDomain);
- ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
- cifs_dbg(FYI, "serverDomain=%s\n", ses->serverDomain);
-
- return;
-}
-
-static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
- struct cifs_ses *ses,
- const struct nls_table *nls_cp)
-{
- int len;
- char *bcc_ptr = *pbcc_area;
-
- cifs_dbg(FYI, "decode sessetup ascii. bleft %d\n", bleft);
-
- len = strnlen(bcc_ptr, bleft);
- if (len >= bleft)
- return;
-
- kfree(ses->serverOS);
-
- ses->serverOS = kmalloc(len + 1, GFP_KERNEL);
- if (ses->serverOS) {
- memcpy(ses->serverOS, bcc_ptr, len);
- ses->serverOS[len] = 0;
- if (strncmp(ses->serverOS, "OS/2", 4) == 0)
- cifs_dbg(FYI, "OS/2 server\n");
- }
-
- bcc_ptr += len + 1;
- bleft -= len + 1;
-
- len = strnlen(bcc_ptr, bleft);
- if (len >= bleft)
- return;
-
- kfree(ses->serverNOS);
-
- ses->serverNOS = kmalloc(len + 1, GFP_KERNEL);
- if (ses->serverNOS) {
- memcpy(ses->serverNOS, bcc_ptr, len);
- ses->serverNOS[len] = 0;
- }
-
- bcc_ptr += len + 1;
- bleft -= len + 1;
-
- len = strnlen(bcc_ptr, bleft);
- if (len > bleft)
- return;
-
- /*
- * No domain field in LANMAN case. Domain is
- * returned by old servers in the SMB negprot response
- *
- * BB For newer servers which do not support Unicode,
- * but thus do return domain here, we could add parsing
- * for it later, but it is not very important
- */
- cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
-}
-#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
struct cifs_ses *ses)
@@ -1292,709 +1037,3 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
return Unspecified;
}
}
-
-struct sess_data {
- unsigned int xid;
- struct cifs_ses *ses;
- struct TCP_Server_Info *server;
- struct nls_table *nls_cp;
- void (*func)(struct sess_data *);
- int result;
-
- /* we will send the SMB in three pieces:
- * a fixed length beginning part, an optional
- * SPNEGO blob (which can be zero length), and a
- * last part which will include the strings
- * and rest of bcc area. This allows us to avoid
- * a large buffer 17K allocation
- */
- int buf0_type;
- struct kvec iov[3];
-};
-
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
-static int
-sess_alloc_buffer(struct sess_data *sess_data, int wct)
-{
- int rc;
- struct cifs_ses *ses = sess_data->ses;
- struct smb_hdr *smb_buf;
-
- rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
- (void **)&smb_buf);
-
- if (rc)
- return rc;
-
- sess_data->iov[0].iov_base = (char *)smb_buf;
- sess_data->iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4;
- /*
- * This variable will be used to clear the buffer
- * allocated above in case of any error in the calling function.
- */
- sess_data->buf0_type = CIFS_SMALL_BUFFER;
-
- /* 2000 big enough to fit max user, domain, NOS name etc. */
- sess_data->iov[2].iov_base = kmalloc(2000, GFP_KERNEL);
- if (!sess_data->iov[2].iov_base) {
- rc = -ENOMEM;
- goto out_free_smb_buf;
- }
-
- return 0;
-
-out_free_smb_buf:
- cifs_small_buf_release(smb_buf);
- sess_data->iov[0].iov_base = NULL;
- sess_data->iov[0].iov_len = 0;
- sess_data->buf0_type = CIFS_NO_BUFFER;
- return rc;
-}
-
-static void
-sess_free_buffer(struct sess_data *sess_data)
-{
- struct kvec *iov = sess_data->iov;
-
- /*
- * Zero the session data before freeing, as it might contain sensitive info (keys, etc).
- * Note that iov[1] is already freed by caller.
- */
- if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
- memzero_explicit(iov[0].iov_base, iov[0].iov_len);
-
- free_rsp_buf(sess_data->buf0_type, iov[0].iov_base);
- sess_data->buf0_type = CIFS_NO_BUFFER;
- kfree_sensitive(iov[2].iov_base);
-}
-
-static int
-sess_establish_session(struct sess_data *sess_data)
-{
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
-
- cifs_server_lock(server);
- if (!server->session_estab) {
- if (server->sign) {
- server->session_key.response =
- kmemdup(ses->auth_key.response,
- ses->auth_key.len, GFP_KERNEL);
- if (!server->session_key.response) {
- cifs_server_unlock(server);
- return -ENOMEM;
- }
- server->session_key.len =
- ses->auth_key.len;
- }
- server->sequence_number = 0x2;
- server->session_estab = true;
- }
- cifs_server_unlock(server);
-
- cifs_dbg(FYI, "CIFS session established successfully\n");
- return 0;
-}
-
-static int
-sess_sendreceive(struct sess_data *sess_data)
-{
- int rc;
- struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
- __u16 count;
- struct kvec rsp_iov = { NULL, 0 };
-
- count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
- be32_add_cpu(&smb_buf->smb_buf_length, count);
- put_bcc(count, smb_buf);
-
- rc = SendReceive2(sess_data->xid, sess_data->ses,
- sess_data->iov, 3 /* num_iovecs */,
- &sess_data->buf0_type,
- CIFS_LOG_ERROR, &rsp_iov);
- cifs_small_buf_release(sess_data->iov[0].iov_base);
- memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
-
- return rc;
-}
-
-static void
-sess_auth_ntlmv2(struct sess_data *sess_data)
-{
- int rc = 0;
- struct smb_hdr *smb_buf;
- SESSION_SETUP_ANDX *pSMB;
- char *bcc_ptr;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
- __u32 capabilities;
- __u16 bytes_remaining;
-
- /* old style NTLM sessionsetup */
- /* wct = 13 */
- rc = sess_alloc_buffer(sess_data, 13);
- if (rc)
- goto out;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- bcc_ptr = sess_data->iov[2].iov_base;
- capabilities = cifs_ssetup_hdr(ses, server, pSMB);
-
- pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
-
- /* LM2 password would be here if we supported it */
- pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
-
- if (ses->user_name != NULL) {
- /* calculate nlmv2 response and session key */
- rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
- if (rc) {
- cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
- goto out;
- }
-
- memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
- ses->auth_key.len - CIFS_SESS_KEY_SIZE);
- bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
-
- /* set case sensitive password length after tilen may get
- * assigned, tilen is 0 otherwise.
- */
- pSMB->req_no_secext.CaseSensitivePasswordLength =
- cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
- } else {
- pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
- }
-
- if (ses->capabilities & CAP_UNICODE) {
- if (!IS_ALIGNED(sess_data->iov[0].iov_len, 2)) {
- *bcc_ptr = 0;
- bcc_ptr++;
- }
- unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
- } else {
- ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
- }
-
-
- sess_data->iov[2].iov_len = (long) bcc_ptr -
- (long) sess_data->iov[2].iov_base;
-
- rc = sess_sendreceive(sess_data);
- if (rc)
- goto out;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
-
- if (smb_buf->WordCount != 3) {
- rc = -EIO;
- cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
- goto out;
- }
-
- if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
- cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
-
- ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
- cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
-
- bytes_remaining = get_bcc(smb_buf);
- bcc_ptr = pByteArea(smb_buf);
-
- /* BB check if Unicode and decode strings */
- if (bytes_remaining == 0) {
- /* no string area to decode, do nothing */
- } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
- /* unicode string area must be word-aligned */
- if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
- ++bcc_ptr;
- --bytes_remaining;
- }
- decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- } else {
- decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- }
-
- rc = sess_establish_session(sess_data);
-out:
- sess_data->result = rc;
- sess_data->func = NULL;
- sess_free_buffer(sess_data);
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = NULL;
-}
-
-#ifdef CONFIG_CIFS_UPCALL
-static void
-sess_auth_kerberos(struct sess_data *sess_data)
-{
- int rc = 0;
- struct smb_hdr *smb_buf;
- SESSION_SETUP_ANDX *pSMB;
- char *bcc_ptr;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
- __u32 capabilities;
- __u16 bytes_remaining;
- struct key *spnego_key = NULL;
- struct cifs_spnego_msg *msg;
- u16 blob_len;
-
- /* extended security */
- /* wct = 12 */
- rc = sess_alloc_buffer(sess_data, 12);
- if (rc)
- goto out;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- bcc_ptr = sess_data->iov[2].iov_base;
- capabilities = cifs_ssetup_hdr(ses, server, pSMB);
-
- spnego_key = cifs_get_spnego_key(ses, server);
- if (IS_ERR(spnego_key)) {
- rc = PTR_ERR(spnego_key);
- spnego_key = NULL;
- goto out;
- }
-
- msg = spnego_key->payload.data[0];
- /*
- * check version field to make sure that cifs.upcall is
- * sending us a response in an expected form
- */
- if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
- cifs_dbg(VFS, "incorrect version of cifs.upcall (expected %d but got %d)\n",
- CIFS_SPNEGO_UPCALL_VERSION, msg->version);
- rc = -EKEYREJECTED;
- goto out_put_spnego_key;
- }
-
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
- GFP_KERNEL);
- if (!ses->auth_key.response) {
- cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
- msg->sesskey_len);
- rc = -ENOMEM;
- goto out_put_spnego_key;
- }
- ses->auth_key.len = msg->sesskey_len;
-
- pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
- capabilities |= CAP_EXTENDED_SECURITY;
- pSMB->req.Capabilities = cpu_to_le32(capabilities);
- sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
- sess_data->iov[1].iov_len = msg->secblob_len;
- pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len);
-
- if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) {
- /* unicode strings must be word aligned */
- if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
- *bcc_ptr = 0;
- bcc_ptr++;
- }
- unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
- unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
- } else {
- ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp);
- ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
- }
-
- sess_data->iov[2].iov_len = (long) bcc_ptr -
- (long) sess_data->iov[2].iov_base;
-
- rc = sess_sendreceive(sess_data);
- if (rc)
- goto out_put_spnego_key;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
-
- if (smb_buf->WordCount != 4) {
- rc = -EIO;
- cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
- goto out_put_spnego_key;
- }
-
- if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
- cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
-
- ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
- cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
-
- bytes_remaining = get_bcc(smb_buf);
- bcc_ptr = pByteArea(smb_buf);
-
- blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
- if (blob_len > bytes_remaining) {
- cifs_dbg(VFS, "bad security blob length %d\n",
- blob_len);
- rc = -EINVAL;
- goto out_put_spnego_key;
- }
- bcc_ptr += blob_len;
- bytes_remaining -= blob_len;
-
- /* BB check if Unicode and decode strings */
- if (bytes_remaining == 0) {
- /* no string area to decode, do nothing */
- } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
- /* unicode string area must be word-aligned */
- if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
- ++bcc_ptr;
- --bytes_remaining;
- }
- decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- } else {
- decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- }
-
- rc = sess_establish_session(sess_data);
-out_put_spnego_key:
- key_invalidate(spnego_key);
- key_put(spnego_key);
-out:
- sess_data->result = rc;
- sess_data->func = NULL;
- sess_free_buffer(sess_data);
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = NULL;
-}
-
-#endif /* ! CONFIG_CIFS_UPCALL */
-
-/*
- * The required kvec buffers have to be allocated before calling this
- * function.
- */
-static int
-_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
-{
- SESSION_SETUP_ANDX *pSMB;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
- __u32 capabilities;
- char *bcc_ptr;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
-
- capabilities = cifs_ssetup_hdr(ses, server, pSMB);
- if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
- cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
- return -ENOSYS;
- }
-
- pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
- capabilities |= CAP_EXTENDED_SECURITY;
- pSMB->req.Capabilities |= cpu_to_le32(capabilities);
-
- bcc_ptr = sess_data->iov[2].iov_base;
- /* unicode strings must be word aligned */
- if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
- *bcc_ptr = 0;
- bcc_ptr++;
- }
- unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
-
- sess_data->iov[2].iov_len = (long) bcc_ptr -
- (long) sess_data->iov[2].iov_base;
-
- return 0;
-}
-
-static void
-sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data);
-
-static void
-sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
-{
- int rc;
- struct smb_hdr *smb_buf;
- SESSION_SETUP_ANDX *pSMB;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
- __u16 bytes_remaining;
- char *bcc_ptr;
- unsigned char *ntlmsspblob = NULL;
- u16 blob_len;
-
- cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
-
- /*
- * if memory allocation is successful, caller of this function
- * frees it.
- */
- ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
- if (!ses->ntlmssp) {
- rc = -ENOMEM;
- goto out;
- }
- ses->ntlmssp->sesskey_per_smbsess = false;
-
- /* wct = 12 */
- rc = sess_alloc_buffer(sess_data, 12);
- if (rc)
- goto out;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
-
- /* Build security blob before we assemble the request */
- rc = build_ntlmssp_negotiate_blob(&ntlmsspblob,
- &blob_len, ses, server,
- sess_data->nls_cp);
- if (rc)
- goto out_free_ntlmsspblob;
-
- sess_data->iov[1].iov_len = blob_len;
- sess_data->iov[1].iov_base = ntlmsspblob;
- pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
-
- rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
- if (rc)
- goto out_free_ntlmsspblob;
-
- rc = sess_sendreceive(sess_data);
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
-
- /* If true, rc here is expected and not an error */
- if (sess_data->buf0_type != CIFS_NO_BUFFER &&
- smb_buf->Status.CifsError ==
- cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
- rc = 0;
-
- if (rc)
- goto out_free_ntlmsspblob;
-
- cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
-
- if (smb_buf->WordCount != 4) {
- rc = -EIO;
- cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
- goto out_free_ntlmsspblob;
- }
-
- ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
- cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
-
- bytes_remaining = get_bcc(smb_buf);
- bcc_ptr = pByteArea(smb_buf);
-
- blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
- if (blob_len > bytes_remaining) {
- cifs_dbg(VFS, "bad security blob length %d\n",
- blob_len);
- rc = -EINVAL;
- goto out_free_ntlmsspblob;
- }
-
- rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
-
-out_free_ntlmsspblob:
- kfree_sensitive(ntlmsspblob);
-out:
- sess_free_buffer(sess_data);
-
- if (!rc) {
- sess_data->func = sess_auth_rawntlmssp_authenticate;
- return;
- }
-
- /* Else error. Cleanup */
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = NULL;
- kfree_sensitive(ses->ntlmssp);
- ses->ntlmssp = NULL;
-
- sess_data->func = NULL;
- sess_data->result = rc;
-}
-
-static void
-sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
-{
- int rc;
- struct smb_hdr *smb_buf;
- SESSION_SETUP_ANDX *pSMB;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
- __u16 bytes_remaining;
- char *bcc_ptr;
- unsigned char *ntlmsspblob = NULL;
- u16 blob_len;
-
- cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
-
- /* wct = 12 */
- rc = sess_alloc_buffer(sess_data, 12);
- if (rc)
- goto out;
-
- /* Build security blob before we assemble the request */
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- smb_buf = (struct smb_hdr *)pSMB;
- rc = build_ntlmssp_auth_blob(&ntlmsspblob,
- &blob_len, ses, server,
- sess_data->nls_cp);
- if (rc)
- goto out_free_ntlmsspblob;
- sess_data->iov[1].iov_len = blob_len;
- sess_data->iov[1].iov_base = ntlmsspblob;
- pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
- /*
- * Make sure that we tell the server that we are using
- * the uid that it just gave us back on the response
- * (challenge)
- */
- smb_buf->Uid = ses->Suid;
-
- rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
- if (rc)
- goto out_free_ntlmsspblob;
-
- rc = sess_sendreceive(sess_data);
- if (rc)
- goto out_free_ntlmsspblob;
-
- pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
- smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
- if (smb_buf->WordCount != 4) {
- rc = -EIO;
- cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
- goto out_free_ntlmsspblob;
- }
-
- if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
- cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
-
- if (ses->Suid != smb_buf->Uid) {
- ses->Suid = smb_buf->Uid;
- cifs_dbg(FYI, "UID changed! new UID = %llu\n", ses->Suid);
- }
-
- bytes_remaining = get_bcc(smb_buf);
- bcc_ptr = pByteArea(smb_buf);
- blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
- if (blob_len > bytes_remaining) {
- cifs_dbg(VFS, "bad security blob length %d\n",
- blob_len);
- rc = -EINVAL;
- goto out_free_ntlmsspblob;
- }
- bcc_ptr += blob_len;
- bytes_remaining -= blob_len;
-
-
- /* BB check if Unicode and decode strings */
- if (bytes_remaining == 0) {
- /* no string area to decode, do nothing */
- } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
- /* unicode string area must be word-aligned */
- if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
- ++bcc_ptr;
- --bytes_remaining;
- }
- decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- } else {
- decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
- sess_data->nls_cp);
- }
-
-out_free_ntlmsspblob:
- kfree_sensitive(ntlmsspblob);
-out:
- sess_free_buffer(sess_data);
-
- if (!rc)
- rc = sess_establish_session(sess_data);
-
- /* Cleanup */
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = NULL;
- kfree_sensitive(ses->ntlmssp);
- ses->ntlmssp = NULL;
-
- sess_data->func = NULL;
- sess_data->result = rc;
-}
-
-static int select_sec(struct sess_data *sess_data)
-{
- int type;
- struct cifs_ses *ses = sess_data->ses;
- struct TCP_Server_Info *server = sess_data->server;
-
- type = cifs_select_sectype(server, ses->sectype);
- cifs_dbg(FYI, "sess setup type %d\n", type);
- if (type == Unspecified) {
- cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
- return -EINVAL;
- }
-
- switch (type) {
- case NTLMv2:
- sess_data->func = sess_auth_ntlmv2;
- break;
- case Kerberos:
-#ifdef CONFIG_CIFS_UPCALL
- sess_data->func = sess_auth_kerberos;
- break;
-#else
- cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
- return -ENOSYS;
-#endif /* CONFIG_CIFS_UPCALL */
- case RawNTLMSSP:
- sess_data->func = sess_auth_rawntlmssp_negotiate;
- break;
- default:
- cifs_dbg(VFS, "secType %d not supported!\n", type);
- return -ENOSYS;
- }
-
- return 0;
-}
-
-int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const struct nls_table *nls_cp)
-{
- int rc = 0;
- struct sess_data *sess_data;
-
- if (ses == NULL) {
- WARN(1, "%s: ses == NULL!", __func__);
- return -EINVAL;
- }
-
- sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
- if (!sess_data)
- return -ENOMEM;
-
- sess_data->xid = xid;
- sess_data->ses = ses;
- sess_data->server = server;
- sess_data->buf0_type = CIFS_NO_BUFFER;
- sess_data->nls_cp = (struct nls_table *) nls_cp;
-
- rc = select_sec(sess_data);
- if (rc)
- goto out;
-
- while (sess_data->func)
- sess_data->func(sess_data);
-
- /* Store result before we free sess_data */
- rc = sess_data->result;
-
-out:
- kfree_sensitive(sess_data);
- return rc;
-}
-#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
diff --git a/fs/smb/client/smb1debug.c b/fs/smb/client/smb1debug.c
new file mode 100644
index 000000000000..e2d013e751e5
--- /dev/null
+++ b/fs/smb/client/smb1debug.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * Copyright (C) International Business Machines Corp., 2000,2005
+ *
+ * Modified by Steve French (sfrench@us.ibm.com)
+ */
+#include "cifsproto.h"
+#include "smb1proto.h"
+#include "cifs_debug.h"
+
+void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server)
+{
+#ifdef CONFIG_CIFS_DEBUG2
+ struct smb_hdr *smb = buf;
+
+ cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d Wct: %d\n",
+ smb->Command, smb->Status.CifsError, smb->Flags,
+ smb->Flags2, smb->Mid, smb->Pid, smb->WordCount);
+ if (!server->ops->check_message(buf, buf_len, server->total_read, server)) {
+ cifs_dbg(VFS, "smb buf %p len %u\n", smb,
+ server->ops->calc_smb_size(smb));
+ }
+#endif /* CONFIG_CIFS_DEBUG2 */
+}
diff --git a/fs/smb/client/smb1encrypt.c b/fs/smb/client/smb1encrypt.c
new file mode 100644
index 000000000000..bf10fdeeedca
--- /dev/null
+++ b/fs/smb/client/smb1encrypt.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ * Encryption and hashing operations relating to NTLM, NTLMv2. See MS-NLMP
+ * for more detailed information
+ *
+ * Copyright (C) International Business Machines Corp., 2005,2013
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ */
+
+#include <linux/fips.h>
+#include <crypto/md5.h>
+#include <crypto/utils.h>
+#include "cifsproto.h"
+#include "smb1proto.h"
+#include "cifs_debug.h"
+
+/*
+ * Calculate and return the CIFS signature based on the mac key and SMB PDU.
+ * The 16 byte signature must be allocated by the caller. Note we only use the
+ * 1st eight bytes and that the smb header signature field on input contains
+ * the sequence number before this function is called. Also, this function
+ * should be called with the server->srv_mutex held.
+ */
+static int cifs_calc_signature(struct smb_rqst *rqst,
+ struct TCP_Server_Info *server, char *signature)
+{
+ struct md5_ctx ctx;
+
+ if (!rqst->rq_iov || !signature || !server)
+ return -EINVAL;
+ if (fips_enabled) {
+ cifs_dbg(VFS,
+ "MD5 signature support is disabled due to FIPS\n");
+ return -EOPNOTSUPP;
+ }
+
+ md5_init(&ctx);
+ md5_update(&ctx, server->session_key.response, server->session_key.len);
+
+ return __cifs_calc_signature(
+ rqst, server, signature,
+ &(struct cifs_calc_sig_ctx){ .md5 = &ctx });
+}
+
+/* must be called with server->srv_mutex held */
+int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+ __u32 *pexpected_response_sequence_number)
+{
+ int rc = 0;
+ char smb_signature[20];
+ struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+
+ if ((cifs_pdu == NULL) || (server == NULL))
+ return -EINVAL;
+
+ spin_lock(&server->srv_lock);
+ if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
+ server->tcpStatus == CifsNeedNegotiate) {
+ spin_unlock(&server->srv_lock);
+ return rc;
+ }
+ spin_unlock(&server->srv_lock);
+
+ if (!server->session_estab) {
+ memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+ return rc;
+ }
+
+ cifs_pdu->Signature.Sequence.SequenceNumber =
+ cpu_to_le32(server->sequence_number);
+ cifs_pdu->Signature.Sequence.Reserved = 0;
+
+ *pexpected_response_sequence_number = ++server->sequence_number;
+ ++server->sequence_number;
+
+ rc = cifs_calc_signature(rqst, server, smb_signature);
+ if (rc)
+ memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+ else
+ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+
+ return rc;
+}
+
+int cifs_verify_signature(struct smb_rqst *rqst,
+ struct TCP_Server_Info *server,
+ __u32 expected_sequence_number)
+{
+ unsigned int rc;
+ char server_response_sig[8];
+ char what_we_think_sig_should_be[20];
+ struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+
+ if (cifs_pdu == NULL || server == NULL)
+ return -EINVAL;
+
+ if (!server->session_estab)
+ return 0;
+
+ if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
+ struct smb_com_lock_req *pSMB =
+ (struct smb_com_lock_req *)cifs_pdu;
+ if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
+ return 0;
+ }
+
+ /* BB what if signatures are supposed to be on for session but
+ server does not send one? BB */
+
+ /* Do not need to verify session setups with signature "BSRSPYL " */
+ if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
+ cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
+ cifs_pdu->Command);
+
+ /* save off the original signature so we can modify the smb and check
+ its signature against what the server sent */
+ memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
+
+ cifs_pdu->Signature.Sequence.SequenceNumber =
+ cpu_to_le32(expected_sequence_number);
+ cifs_pdu->Signature.Sequence.Reserved = 0;
+
+ cifs_server_lock(server);
+ rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
+ cifs_server_unlock(server);
+
+ if (rc)
+ return rc;
+
+/* cifs_dump_mem("what we think it should be: ",
+ what_we_think_sig_should_be, 16); */
+
+ if (crypto_memneq(server_response_sig, what_we_think_sig_should_be, 8))
+ return -EACCES;
+ else
+ return 0;
+
+}
diff --git a/fs/smb/client/smb1maperror.c b/fs/smb/client/smb1maperror.c
new file mode 100644
index 000000000000..74530088d17d
--- /dev/null
+++ b/fs/smb/client/smb1maperror.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2002,2008
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * Error mapping routines from Samba libsmb/errormap.c
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ */
+
+#include <linux/bsearch.h>
+#include "cifsproto.h"
+#include "smb1proto.h"
+#include "smberr.h"
+#include "nterr.h"
+#include "cifs_debug.h"
+
+static __always_inline int smb1_posix_error_cmp(const void *_key, const void *_pivot)
+{
+ __u16 key = *(__u16 *)_key;
+ const struct smb_to_posix_error *pivot = _pivot;
+
+ if (key < pivot->smb_err)
+ return -1;
+ if (key > pivot->smb_err)
+ return 1;
+ return 0;
+}
+
+static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
+/*
+ * Automatically generated by the `gen_smb1_mapping` script,
+ * sorted by DOS error code (ascending).
+ */
+#include "smb1_err_dos_map.c"
+};
+
+static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
+/*
+ * Automatically generated by the `gen_smb1_mapping` script,
+ * sorted by SRV error code (ascending).
+ */
+#include "smb1_err_srv_map.c"
+};
+
+/*****************************************************************************
+ *convert a NT status code to a dos class/code
+ *****************************************************************************/
+
+static __always_inline int ntstatus_to_dos_cmp(const void *_key, const void *_pivot)
+{
+ __u32 key = *(__u32 *)_key;
+ const struct ntstatus_to_dos_err *pivot = _pivot;
+
+ if (key < pivot->ntstatus)
+ return -1;
+ if (key > pivot->ntstatus)
+ return 1;
+ return 0;
+}
+
+/* NT status -> dos error map */
+static const struct ntstatus_to_dos_err ntstatus_to_dos_map[] = {
+/*
+ * Automatically generated by the `gen_smb1_mapping` script,
+ * sorted by NT status code (ascending).
+ */
+#include "smb1_mapping_table.c"
+};
+
+static const struct ntstatus_to_dos_err *
+search_ntstatus_to_dos_map(__u32 ntstatus)
+{
+ return __inline_bsearch(&ntstatus, ntstatus_to_dos_map,
+ ARRAY_SIZE(ntstatus_to_dos_map),
+ sizeof(struct ntstatus_to_dos_err),
+ ntstatus_to_dos_cmp);
+}
+
+static const struct smb_to_posix_error *
+search_mapping_table_ERRDOS(__u16 smb_err)
+{
+ return __inline_bsearch(&smb_err, mapping_table_ERRDOS,
+ ARRAY_SIZE(mapping_table_ERRDOS),
+ sizeof(struct smb_to_posix_error),
+ smb1_posix_error_cmp);
+}
+
+static const struct smb_to_posix_error *
+search_mapping_table_ERRSRV(__u16 smb_err)
+{
+ return __inline_bsearch(&smb_err, mapping_table_ERRSRV,
+ ARRAY_SIZE(mapping_table_ERRSRV),
+ sizeof(struct smb_to_posix_error),
+ smb1_posix_error_cmp);
+}
+
+int
+map_smb_to_linux_error(char *buf, bool logErr)
+{
+ struct smb_hdr *smb = (struct smb_hdr *)buf;
+ int rc = -EIO; /* if transport error smb error may not be set */
+ __u8 smberrclass;
+ __u16 smberrcode;
+ const struct smb_to_posix_error *err_map = NULL;
+
+ /* BB if NT Status codes - map NT BB */
+
+ /* old style smb error codes */
+ if (smb->Status.CifsError == 0)
+ return 0;
+
+ if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
+ /* translate the newer STATUS codes to old style SMB errors
+ * and then to POSIX errors */
+ __u32 err = le32_to_cpu(smb->Status.CifsError);
+ const struct ntstatus_to_dos_err *map = search_ntstatus_to_dos_map(err);
+
+ if (map) {
+ if ((logErr && err != NT_STATUS_MORE_PROCESSING_REQUIRED) ||
+ (cifsFYI & CIFS_RC))
+ pr_notice("Status code returned 0x%08x %s\n",
+ map->ntstatus, map->nt_errstr);
+
+ smberrclass = map->dos_class;
+ smberrcode = map->dos_code;
+ } else {
+ smberrclass = ERRHRD;
+ smberrcode = ERRgeneral;
+ }
+ } else {
+ smberrclass = smb->Status.DosError.ErrorClass;
+ smberrcode = le16_to_cpu(smb->Status.DosError.Error);
+ }
+
+ /* old style errors */
+
+ if (smberrclass == ERRDOS) {
+ /* DOS class smb error codes - map DOS */
+ /* 1 byte field no need to byte reverse */
+ err_map = search_mapping_table_ERRDOS(smberrcode);
+ } else if (smberrclass == ERRSRV) {
+ /* server class of error codes */
+ err_map = search_mapping_table_ERRSRV(smberrcode);
+ }
+ if (err_map)
+ rc = err_map->posix_code;
+ /* else ERRHRD class errors or junk - return EIO */
+
+ /* special cases for NT status codes which cannot be translated to DOS codes */
+ if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
+ __u32 err = le32_to_cpu(smb->Status.CifsError);
+ if (err == (NT_STATUS_NOT_A_REPARSE_POINT))
+ rc = -ENODATA;
+ else if (err == (NT_STATUS_PRIVILEGE_NOT_HELD))
+ rc = -EPERM;
+ }
+
+ cifs_dbg(FYI, "Mapping smb error code 0x%x to POSIX err %d\n",
+ le32_to_cpu(smb->Status.CifsError), rc);
+
+ /* generic corrective action e.g. reconnect SMB session on
+ * ERRbaduid could be added */
+
+ if (rc == -EIO)
+ smb_EIO2(smb_eio_trace_smb1_received_error,
+ le32_to_cpu(smb->Status.CifsError),
+ le16_to_cpu(smb->Flags2));
+ return rc;
+}
+
+int
+map_and_check_smb_error(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid, bool logErr)
+{
+ int rc;
+ struct smb_hdr *smb = (struct smb_hdr *)mid->resp_buf;
+
+ rc = map_smb_to_linux_error((char *)smb, logErr);
+ if (rc == -EACCES && !(smb->Flags2 & SMBFLG2_ERR_STATUS)) {
+ /* possible ERRBaduid */
+ __u8 class = smb->Status.DosError.ErrorClass;
+ __u16 code = le16_to_cpu(smb->Status.DosError.Error);
+
+ /* switch can be used to handle different errors */
+ if (class == ERRSRV && code == ERRbaduid) {
+ cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
+ code);
+ cifs_signal_cifsd_for_reconnect(server, false);
+ }
+ }
+
+ return rc;
+}
+
+#define DEFINE_CHECK_SORT_FUNC(__array, __field) \
+static int __init __array ## _is_sorted(void) \
+{ \
+ unsigned int i; \
+ \
+ /* Check whether the array is sorted in ascending order */ \
+ for (i = 1; i < ARRAY_SIZE(__array); i++) { \
+ if (__array[i].__field >= \
+ __array[i - 1].__field) \
+ continue; \
+ \
+ pr_err(#__array " array order is incorrect\n"); \
+ return -EINVAL; \
+ } \
+ \
+ return 0; \
+}
+
+/* ntstatus_to_dos_map_is_sorted */
+DEFINE_CHECK_SORT_FUNC(ntstatus_to_dos_map, ntstatus);
+/* mapping_table_ERRDOS_is_sorted */
+DEFINE_CHECK_SORT_FUNC(mapping_table_ERRDOS, smb_err);
+/* mapping_table_ERRSRV_is_sorted */
+DEFINE_CHECK_SORT_FUNC(mapping_table_ERRSRV, smb_err);
+
+int __init smb1_init_maperror(void)
+{
+ int rc;
+
+ rc = ntstatus_to_dos_map_is_sorted();
+ if (rc)
+ return rc;
+
+ rc = mapping_table_ERRDOS_is_sorted();
+ if (rc)
+ return rc;
+
+ rc = mapping_table_ERRSRV_is_sorted();
+ if (rc)
+ return rc;
+
+ return rc;
+}
+
+#if IS_ENABLED(CONFIG_SMB1_KUNIT_TESTS)
+#define EXPORT_SYMBOL_FOR_SMB_TEST(sym) \
+ EXPORT_SYMBOL_FOR_MODULES(sym, "smb1maperror_test")
+
+const struct ntstatus_to_dos_err *
+search_ntstatus_to_dos_map_test(__u32 ntstatus)
+{
+ return search_ntstatus_to_dos_map(ntstatus);
+}
+EXPORT_SYMBOL_FOR_SMB_TEST(search_ntstatus_to_dos_map_test);
+
+const struct ntstatus_to_dos_err *
+ntstatus_to_dos_map_test = ntstatus_to_dos_map;
+EXPORT_SYMBOL_FOR_SMB_TEST(ntstatus_to_dos_map_test);
+
+unsigned int ntstatus_to_dos_num = ARRAY_SIZE(ntstatus_to_dos_map);
+EXPORT_SYMBOL_FOR_SMB_TEST(ntstatus_to_dos_num);
+
+const struct smb_to_posix_error *
+search_mapping_table_ERRDOS_test(__u16 smb_err)
+{
+ return search_mapping_table_ERRDOS(smb_err);
+}
+EXPORT_SYMBOL_FOR_SMB_TEST(search_mapping_table_ERRDOS_test);
+
+const struct smb_to_posix_error *
+mapping_table_ERRDOS_test = mapping_table_ERRDOS;
+EXPORT_SYMBOL_FOR_SMB_TEST(mapping_table_ERRDOS_test);
+
+unsigned int mapping_table_ERRDOS_num = ARRAY_SIZE(mapping_table_ERRDOS);
+EXPORT_SYMBOL_FOR_SMB_TEST(mapping_table_ERRDOS_num);
+
+const struct smb_to_posix_error *
+search_mapping_table_ERRSRV_test(__u16 smb_err)
+{
+ return search_mapping_table_ERRSRV(smb_err);
+}
+EXPORT_SYMBOL_FOR_SMB_TEST(search_mapping_table_ERRSRV_test);
+
+const struct smb_to_posix_error *
+mapping_table_ERRSRV_test = mapping_table_ERRSRV;
+EXPORT_SYMBOL_FOR_SMB_TEST(mapping_table_ERRSRV_test);
+
+unsigned int mapping_table_ERRSRV_num = ARRAY_SIZE(mapping_table_ERRSRV);
+EXPORT_SYMBOL_FOR_SMB_TEST(mapping_table_ERRSRV_num);
+#endif
diff --git a/fs/smb/client/smb1maperror_test.c b/fs/smb/client/smb1maperror_test.c
new file mode 100644
index 000000000000..2caaf11228ef
--- /dev/null
+++ b/fs/smb/client/smb1maperror_test.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * KUnit tests of SMB1 maperror
+ *
+ * Copyright (C) 2026 KylinSoft Co., Ltd. All rights reserved.
+ * Author(s): Youling Tang <tangyouling@kylinos.cn>
+ * ChenXiaoSong <chenxiaosong@kylinos.cn>
+ *
+ */
+
+#include <kunit/test.h>
+#include "smb1proto.h"
+#include "nterr.h"
+#include "smberr.h"
+
+#define DEFINE_CHECK_SEARCH_FUNC(__struct_name, __field, \
+ __array, __num) \
+static void check_search_ ## __array(struct kunit *test) \
+{ \
+ unsigned int i; \
+ const struct __struct_name *expect, *result; \
+ \
+ for (i = 0; i < __num; i++) { \
+ expect = &__array ## _test[i]; \
+ result = search_ ## __array ## _test(expect->__field); \
+ KUNIT_ASSERT_NOT_NULL(test, result); \
+ test_cmp_ ## __struct_name(test, expect, result); \
+ } \
+}
+
+static void
+test_cmp_ntstatus_to_dos_err(struct kunit *test,
+ const struct ntstatus_to_dos_err *expect,
+ const struct ntstatus_to_dos_err *result)
+{
+ KUNIT_EXPECT_EQ(test, expect->dos_class, result->dos_class);
+ KUNIT_EXPECT_EQ(test, expect->dos_code, result->dos_code);
+ KUNIT_EXPECT_EQ(test, expect->ntstatus, result->ntstatus);
+ KUNIT_EXPECT_STREQ(test, expect->nt_errstr, result->nt_errstr);
+}
+
+static void
+test_cmp_smb_to_posix_error(struct kunit *test,
+ const struct smb_to_posix_error *expect,
+ const struct smb_to_posix_error *result)
+{
+ KUNIT_EXPECT_EQ(test, expect->smb_err, result->smb_err);
+ KUNIT_EXPECT_EQ(test, expect->posix_code, result->posix_code);
+}
+
+/* check_search_ntstatus_to_dos_map */
+DEFINE_CHECK_SEARCH_FUNC(ntstatus_to_dos_err, ntstatus, ntstatus_to_dos_map,
+ ntstatus_to_dos_num);
+/* check_search_mapping_table_ERRDOS */
+DEFINE_CHECK_SEARCH_FUNC(smb_to_posix_error, smb_err, mapping_table_ERRDOS,
+ mapping_table_ERRDOS_num);
+/* check_search_mapping_table_ERRSRV */
+DEFINE_CHECK_SEARCH_FUNC(smb_to_posix_error, smb_err, mapping_table_ERRSRV,
+ mapping_table_ERRSRV_num);
+
+static struct kunit_case maperror_test_cases[] = {
+ KUNIT_CASE(check_search_ntstatus_to_dos_map),
+ KUNIT_CASE(check_search_mapping_table_ERRDOS),
+ KUNIT_CASE(check_search_mapping_table_ERRSRV),
+ {}
+};
+
+static struct kunit_suite maperror_suite = {
+ .name = "smb1_maperror",
+ .test_cases = maperror_test_cases,
+};
+
+kunit_test_suite(maperror_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests of SMB1 maperror");
diff --git a/fs/smb/client/smb1misc.c b/fs/smb/client/smb1misc.c
new file mode 100644
index 000000000000..ba56023010d8
--- /dev/null
+++ b/fs/smb/client/smb1misc.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2008
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ */
+
+#include "smb1proto.h"
+#include "smberr.h"
+#include "nterr.h"
+#include "cifs_debug.h"
+
+/* NB: MID can not be set if treeCon not passed in, in that
+ case it is responsibility of caller to set the mid */
+unsigned int
+header_assemble(struct smb_hdr *buffer, char smb_command,
+ const struct cifs_tcon *treeCon, int word_count
+ /* length of fixed section (word count) in two byte units */)
+{
+ unsigned int in_len;
+ char *temp = (char *) buffer;
+
+ memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
+
+ in_len = (2 * word_count) + sizeof(struct smb_hdr) +
+ 2 /* for bcc field itself */;
+
+ buffer->Protocol[0] = 0xFF;
+ buffer->Protocol[1] = 'S';
+ buffer->Protocol[2] = 'M';
+ buffer->Protocol[3] = 'B';
+ buffer->Command = smb_command;
+ buffer->Flags = 0x00; /* case sensitive */
+ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
+ buffer->Pid = cpu_to_le16((__u16)current->tgid);
+ buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
+ if (treeCon) {
+ buffer->Tid = treeCon->tid;
+ if (treeCon->ses) {
+ if (treeCon->ses->capabilities & CAP_UNICODE)
+ buffer->Flags2 |= SMBFLG2_UNICODE;
+ if (treeCon->ses->capabilities & CAP_STATUS32)
+ buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+ /* Uid is not converted */
+ buffer->Uid = treeCon->ses->Suid;
+ if (treeCon->ses->server)
+ buffer->Mid = get_next_mid(treeCon->ses->server);
+ }
+ if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
+ buffer->Flags2 |= SMBFLG2_DFS;
+ if (treeCon->nocase)
+ buffer->Flags |= SMBFLG_CASELESS;
+ if ((treeCon->ses) && (treeCon->ses->server))
+ if (treeCon->ses->server->sign)
+ buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+ }
+
+/* endian conversion of flags is now done just before sending */
+ buffer->WordCount = (char) word_count;
+ return in_len;
+}
+
+bool
+is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
+{
+ struct smb_hdr *buf = (struct smb_hdr *)buffer;
+ struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
+ struct TCP_Server_Info *pserver;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *pCifsInode;
+ struct cifsFileInfo *netfile;
+
+ cifs_dbg(FYI, "Checking for oplock break or dnotify response\n");
+ if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
+ (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
+ struct smb_com_transaction_change_notify_rsp *pSMBr =
+ (struct smb_com_transaction_change_notify_rsp *)buf;
+ struct file_notify_information *pnotify;
+ __u32 data_offset = 0;
+ size_t len = srv->total_read - srv->pdu_size;
+
+ if (get_bcc(buf) > sizeof(struct file_notify_information)) {
+ data_offset = le32_to_cpu(pSMBr->DataOffset);
+
+ if (data_offset >
+ len - sizeof(struct file_notify_information)) {
+ cifs_dbg(FYI, "Invalid data_offset %u\n",
+ data_offset);
+ return true;
+ }
+ pnotify = (struct file_notify_information *)
+ ((char *)&pSMBr->hdr.Protocol + data_offset);
+ cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
+ pnotify->FileName, pnotify->Action);
+ /* cifs_dump_mem("Rcvd notify Data: ",buf,
+ sizeof(struct smb_hdr)+60); */
+ return true;
+ }
+ if (pSMBr->hdr.Status.CifsError) {
+ cifs_dbg(FYI, "notify err 0x%x\n",
+ pSMBr->hdr.Status.CifsError);
+ return true;
+ }
+ return false;
+ }
+ if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
+ return false;
+ if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
+ /* no sense logging error on invalid handle on oplock
+ break - harmless race between close request and oplock
+ break response is expected from time to time writing out
+ large dirty files cached on the client */
+ if ((NT_STATUS_INVALID_HANDLE) ==
+ le32_to_cpu(pSMB->hdr.Status.CifsError)) {
+ cifs_dbg(FYI, "Invalid handle on oplock break\n");
+ return true;
+ } else if (ERRbadfid ==
+ le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
+ return true;
+ } else {
+ return false; /* on valid oplock brk we get "request" */
+ }
+ }
+ if (pSMB->hdr.WordCount != 8)
+ return false;
+
+ cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
+ pSMB->LockType, pSMB->OplockLevel);
+ if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
+ return false;
+
+ /* If server is a channel, select the primary channel */
+ pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
+ if (cifs_ses_exiting(ses))
+ continue;
+ list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+ if (tcon->tid != buf->Tid)
+ continue;
+
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+ spin_lock(&tcon->open_file_lock);
+ list_for_each_entry(netfile, &tcon->openFileList, tlist) {
+ if (pSMB->Fid != netfile->fid.netfid)
+ continue;
+
+ cifs_dbg(FYI, "file id match, oplock break\n");
+ pCifsInode = CIFS_I(d_inode(netfile->dentry));
+
+ set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
+ &pCifsInode->flags);
+
+ netfile->oplock_epoch = 0;
+ netfile->oplock_level = pSMB->OplockLevel;
+ netfile->oplock_break_cancelled = false;
+ cifs_queue_oplock_break(netfile);
+
+ spin_unlock(&tcon->open_file_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ return true;
+ }
+ spin_unlock(&tcon->open_file_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ cifs_dbg(FYI, "No matching file for oplock break\n");
+ return true;
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
+ return true;
+}
+
+/*
+ * calculate the size of the SMB message based on the fixed header
+ * portion, the number of word parameters and the data portion of the message
+ */
+unsigned int
+smbCalcSize(void *buf)
+{
+ struct smb_hdr *ptr = buf;
+ return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
+ 2 /* size of the bcc field */ + get_bcc(ptr));
+}
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 0adeec652dc1..e198e3dda917 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -7,15 +7,125 @@
#include <linux/pagemap.h>
#include <linux/vfs.h>
+#include <linux/fs_struct.h>
#include <uapi/linux/magic.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
-#include "cifspdu.h"
#include "cifs_unicode.h"
#include "fs_context.h"
#include "nterr.h"
#include "smberr.h"
+#include "reparse.h"
+
+void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
+{
+ /*
+ * If we are reconnecting then should we check to see if
+ * any requested capabilities changed locally e.g. via
+ * remount but we can not do much about it here
+ * if they have (even if we could detect it by the following)
+ * Perhaps we could add a backpointer to array of sb from tcon
+ * or if we change to make all sb to same share the same
+ * sb as NFS - then we only have one backpointer to sb.
+ * What if we wanted to mount the server share twice once with
+ * and once without posixacls or posix paths?
+ */
+ __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+
+ if (ctx && ctx->no_linux_ext) {
+ tcon->fsUnixInfo.Capability = 0;
+ tcon->unix_ext = 0; /* Unix Extensions disabled */
+ cifs_dbg(FYI, "Linux protocol extensions disabled\n");
+ return;
+ } else if (ctx)
+ tcon->unix_ext = 1; /* Unix Extensions supported */
+
+ if (!tcon->unix_ext) {
+ cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
+ return;
+ }
+
+ if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
+ __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+
+ cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
+ /*
+ * check for reconnect case in which we do not
+ * want to change the mount behavior if we can avoid it
+ */
+ if (ctx == NULL) {
+ /*
+ * turn off POSIX ACL and PATHNAMES if not set
+ * originally at mount time
+ */
+ if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
+ cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+ if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
+ if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+ cifs_dbg(VFS, "POSIXPATH support change\n");
+ cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+ } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
+ cifs_dbg(VFS, "possible reconnect error\n");
+ cifs_dbg(VFS, "server disabled POSIX path support\n");
+ }
+ }
+
+ if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
+ cifs_dbg(VFS, "per-share encryption not supported yet\n");
+
+ cap &= CIFS_UNIX_CAP_MASK;
+ if (ctx && ctx->no_psx_acl)
+ cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+ else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
+ cifs_dbg(FYI, "negotiated posix acl support\n");
+ if (cifs_sb) {
+ atomic_or(CIFS_MOUNT_POSIXACL,
+ &cifs_sb->mnt_cifs_flags);
+ }
+ }
+
+ if (ctx && ctx->posix_paths == 0)
+ cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+ else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ cifs_dbg(FYI, "negotiate posix pathnames\n");
+ if (cifs_sb) {
+ atomic_or(CIFS_MOUNT_POSIX_PATHS,
+ &cifs_sb->mnt_cifs_flags);
+ }
+ }
+
+ cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
+#ifdef CONFIG_CIFS_DEBUG2
+ if (cap & CIFS_UNIX_FCNTL_CAP)
+ cifs_dbg(FYI, "FCNTL cap\n");
+ if (cap & CIFS_UNIX_EXTATTR_CAP)
+ cifs_dbg(FYI, "EXTATTR cap\n");
+ if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+ cifs_dbg(FYI, "POSIX path cap\n");
+ if (cap & CIFS_UNIX_XATTR_CAP)
+ cifs_dbg(FYI, "XATTR cap\n");
+ if (cap & CIFS_UNIX_POSIX_ACL_CAP)
+ cifs_dbg(FYI, "POSIX ACL cap\n");
+ if (cap & CIFS_UNIX_LARGE_READ_CAP)
+ cifs_dbg(FYI, "very large read cap\n");
+ if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
+ cifs_dbg(FYI, "very large write cap\n");
+ if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
+ cifs_dbg(FYI, "transport encryption cap\n");
+ if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
+ cifs_dbg(FYI, "mandatory transport encryption cap\n");
+#endif /* CIFS_DEBUG2 */
+ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+ if (ctx == NULL)
+ cifs_dbg(FYI, "resetting capabilities failed\n");
+ else
+ cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n");
+
+ }
+ }
+}
/*
* An NT cancel request header looks just like the original request except:
@@ -28,20 +138,25 @@
* SMB_COM_NT_CANCEL request and then sends it.
*/
static int
-send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
- struct mid_q_entry *mid)
+send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, struct mid_q_entry *mid,
+ unsigned int xid)
{
- int rc = 0;
struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+ struct kvec iov[1];
+ struct smb_rqst crqst = { .rq_iov = iov, .rq_nvec = 1 };
+ int rc = 0;
- /* -4 for RFC1001 length and +2 for BCC field */
- in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2);
+ /* +2 for BCC field */
in_buf->Command = SMB_COM_NT_CANCEL;
in_buf->WordCount = 0;
put_bcc(0, in_buf);
+ iov[0].iov_base = in_buf;
+ iov[0].iov_len = sizeof(struct smb_hdr) + 2;
+
cifs_server_lock(server);
- rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+ rc = cifs_sign_rqst(&crqst, server, &mid->sequence_number);
if (rc) {
cifs_server_unlock(server);
return rc;
@@ -53,7 +168,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
* after signing here.
*/
--server->sequence_number;
- rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+ rc = __smb_send_rqst(server, 1, &crqst);
if (rc < 0)
server->sequence_number--;
@@ -65,6 +180,46 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
return rc;
}
+/*
+ * Send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to
+ * return.
+ */
+static int
+send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, struct mid_q_entry *mid,
+ unsigned int xid)
+{
+ struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+ unsigned int in_len = rqst->rq_iov[0].iov_len;
+ LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
+ int rc;
+
+ /* We just modify the current in_buf to change
+ * the type of lock from LOCKING_ANDX_SHARED_LOCK
+ * or LOCKING_ANDX_EXCLUSIVE_LOCK to
+ * LOCKING_ANDX_CANCEL_LOCK.
+ */
+ pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
+ pSMB->Timeout = 0;
+ pSMB->hdr.Mid = get_next_mid(ses->server);
+
+ rc = SendReceive(xid, ses, in_buf, in_len, NULL, NULL, 0);
+ if (rc == -ENOLCK)
+ rc = 0; /* If we get back -ENOLCK, it probably means we managed
+ * to cancel the lock command before it took effect.
+ */
+ return rc;
+}
+
+static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, struct mid_q_entry *mid,
+ unsigned int xid)
+{
+ if (mid->sr_flags & CIFS_WINDOWS_LOCK)
+ return send_lock_cancel(ses, server, rqst, mid, xid);
+ return send_nt_cancel(ses, server, rqst, mid, xid);
+}
+
static bool
cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
{
@@ -94,17 +249,17 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
struct smb_hdr *buf = (struct smb_hdr *)buffer;
struct mid_q_entry *mid;
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry(mid, &server->pending_mid_q, qhead) {
if (compare_mid(mid->mid, buf) &&
mid->mid_state == MID_REQUEST_SUBMITTED &&
le16_to_cpu(mid->command) == buf->Command) {
- kref_get(&mid->refcount);
- spin_unlock(&server->mid_lock);
+ smb_get_mid(mid);
+ spin_unlock(&server->mid_queue_lock);
return mid;
}
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
return NULL;
}
@@ -168,10 +323,9 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
__u16 last_mid, cur_mid;
bool collision, reconnect = false;
- spin_lock(&server->mid_lock);
-
+ spin_lock(&server->mid_counter_lock);
/* mid is 16 bit only for CIFS/SMB */
- cur_mid = (__u16)((server->CurrentMid) & 0xffff);
+ cur_mid = (__u16)((server->current_mid) & 0xffff);
/* we do not want to loop forever */
last_mid = cur_mid;
cur_mid++;
@@ -197,6 +351,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
cur_mid++;
num_mids = 0;
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
++num_mids;
if (mid_entry->mid == cur_mid &&
@@ -206,6 +361,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
break;
}
}
+ spin_unlock(&server->mid_queue_lock);
/*
* if we have more than 32k mids in the list, then something
@@ -222,12 +378,12 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
if (!collision) {
mid = (__u64)cur_mid;
- server->CurrentMid = mid;
+ server->current_mid = mid;
break;
}
cur_mid++;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_counter_lock);
if (reconnect) {
cifs_signal_cifsd_for_reconnect(server, false);
@@ -236,186 +392,16 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
return mid;
}
-/*
- return codes:
- 0 not a transact2, or all data present
- >0 transact2 with that much data missing
- -EINVAL invalid transact2
- */
-static int
-check2ndT2(char *buf)
-{
- struct smb_hdr *pSMB = (struct smb_hdr *)buf;
- struct smb_t2_rsp *pSMBt;
- int remaining;
- __u16 total_data_size, data_in_this_rsp;
-
- if (pSMB->Command != SMB_COM_TRANSACTION2)
- return 0;
-
- /* check for plausible wct, bcc and t2 data and parm sizes */
- /* check for parm and data offset going beyond end of smb */
- if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
- cifs_dbg(FYI, "Invalid transact2 word count\n");
- return -EINVAL;
- }
-
- pSMBt = (struct smb_t2_rsp *)pSMB;
-
- total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
- data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
- if (total_data_size == data_in_this_rsp)
- return 0;
- else if (total_data_size < data_in_this_rsp) {
- cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
- total_data_size, data_in_this_rsp);
- return -EINVAL;
- }
-
- remaining = total_data_size - data_in_this_rsp;
-
- cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
- remaining);
- if (total_data_size > CIFSMaxBufSize) {
- cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
- total_data_size, CIFSMaxBufSize);
- return -EINVAL;
- }
- return remaining;
-}
-
-static int
-coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
-{
- struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
- struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
- char *data_area_of_tgt;
- char *data_area_of_src;
- int remaining;
- unsigned int byte_count, total_in_tgt;
- __u16 tgt_total_cnt, src_total_cnt, total_in_src;
-
- src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
- tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
-
- if (tgt_total_cnt != src_total_cnt)
- cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
- src_total_cnt, tgt_total_cnt);
-
- total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
- remaining = tgt_total_cnt - total_in_tgt;
-
- if (remaining < 0) {
- cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
- tgt_total_cnt, total_in_tgt);
- return -EPROTO;
- }
-
- if (remaining == 0) {
- /* nothing to do, ignore */
- cifs_dbg(FYI, "no more data remains\n");
- return 0;
- }
-
- total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
- if (remaining < total_in_src)
- cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
-
- /* find end of first SMB data area */
- data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
- get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
-
- /* validate target area */
- data_area_of_src = (char *)&pSMBs->hdr.Protocol +
- get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
-
- data_area_of_tgt += total_in_tgt;
-
- total_in_tgt += total_in_src;
- /* is the result too big for the field? */
- if (total_in_tgt > USHRT_MAX) {
- cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
- total_in_tgt);
- return -EPROTO;
- }
- put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
-
- /* fix up the BCC */
- byte_count = get_bcc(target_hdr);
- byte_count += total_in_src;
- /* is the result too big for the field? */
- if (byte_count > USHRT_MAX) {
- cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
- return -EPROTO;
- }
- put_bcc(byte_count, target_hdr);
-
- byte_count = be32_to_cpu(target_hdr->smb_buf_length);
- byte_count += total_in_src;
- /* don't allow buffer to overflow */
- if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
- byte_count);
- return -ENOBUFS;
- }
- target_hdr->smb_buf_length = cpu_to_be32(byte_count);
-
- /* copy second buffer into end of first buffer */
- memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
-
- if (remaining != total_in_src) {
- /* more responses to go */
- cifs_dbg(FYI, "waiting for more secondary responses\n");
- return 1;
- }
-
- /* we are done */
- cifs_dbg(FYI, "found the last secondary response\n");
- return 0;
-}
-
static void
cifs_downgrade_oplock(struct TCP_Server_Info *server,
struct cifsInodeInfo *cinode, __u32 oplock,
__u16 epoch, bool *purge_cache)
{
+ lockdep_assert_held(&cinode->open_file_lock);
cifs_set_oplock_level(cinode, oplock);
}
static bool
-cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
- char *buf, int malformed)
-{
- if (malformed)
- return false;
- if (check2ndT2(buf) <= 0)
- return false;
- mid->multiRsp = true;
- if (mid->resp_buf) {
- /* merge response - fix up 1st*/
- malformed = coalesce_t2(buf, mid->resp_buf);
- if (malformed > 0)
- return true;
- /* All parts received or packet is malformed. */
- mid->multiEnd = true;
- dequeue_mid(mid, malformed);
- return true;
- }
- if (!server->large_buf) {
- /*FIXME: switch to already allocated largebuf?*/
- cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
- } else {
- /* Have first buffer */
- mid->resp_buf = buf;
- mid->large_buf = true;
- server->bigbuf = NULL;
- }
- return true;
-}
-
-static bool
cifs_need_neg(struct TCP_Server_Info *server)
{
return server->maxBuf == 0;
@@ -432,7 +418,7 @@ cifs_negotiate(const unsigned int xid,
}
static unsigned int
-cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+smb1_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
struct TCP_Server_Info *server = tcon->ses->server;
@@ -458,7 +444,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
(!(server->capabilities & CAP_UNIX) && server->sign))
wsize = min_t(unsigned int, wsize,
- server->maxBuf - sizeof(WRITE_REQ) + 4);
+ server->maxBuf - sizeof(WRITE_REQ));
/* hard limit of CIFS_MAX_WSIZE */
wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
@@ -467,7 +453,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
}
static unsigned int
-cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+smb1_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
struct TCP_Server_Info *server = tcon->ses->server;
@@ -522,7 +508,7 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
FILE_ALL_INFO *file_info;
- file_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+ file_info = kmalloc_obj(FILE_ALL_INFO);
if (file_info == NULL)
return -ENOMEM;
@@ -543,40 +529,178 @@ static int cifs_query_path_info(const unsigned int xid,
const char *full_path,
struct cifs_open_info_data *data)
{
- int rc;
+ int rc = -EOPNOTSUPP;
FILE_ALL_INFO fi = {};
+ struct cifs_search_info search_info = {};
+ bool non_unicode_wildcard = false;
data->reparse_point = false;
data->adjust_tz = false;
- /* could do find first instead but this returns more info */
- rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls,
- cifs_remap(cifs_sb));
/*
- * BB optimize code so we do not make the above call when server claims
- * no NT SMB support and the above call failed at least once - set flag
- * in tcon or mount.
+ * First try CIFSSMBQPathInfo() function which returns more info
+ * (NumberOfLinks) than CIFSFindFirst() fallback function.
+ * Some servers like Win9x do not support SMB_QUERY_FILE_ALL_INFO over
+ * TRANS2_QUERY_PATH_INFORMATION, but supports it with filehandle over
+ * TRANS2_QUERY_FILE_INFORMATION (function CIFSSMBQFileInfo(). But SMB
+ * Open command on non-NT servers works only for files, does not work
+ * for directories. And moreover Win9x SMB server returns bogus data in
+ * SMB_QUERY_FILE_ALL_INFO Attributes field. So for non-NT servers,
+ * do not even use CIFSSMBQPathInfo() or CIFSSMBQFileInfo() function.
+ */
+ if (tcon->ses->capabilities & CAP_NT_SMBS)
+ rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */,
+ cifs_sb->local_nls, cifs_remap(cifs_sb));
+
+ /*
+ * Non-UNICODE variant of fallback functions below expands wildcards,
+ * so they cannot be used for querying paths with wildcard characters.
*/
- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+ if (rc && !(tcon->ses->capabilities & CAP_UNICODE) && strpbrk(full_path, "*?\"><"))
+ non_unicode_wildcard = true;
+
+ /*
+ * Then fallback to CIFSFindFirst() which works also with non-NT servers
+ * but does not does not provide NumberOfLinks.
+ */
+ if ((rc == -EOPNOTSUPP || rc == -EINVAL) &&
+ !non_unicode_wildcard) {
+ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find))
+ search_info.info_level = SMB_FIND_FILE_INFO_STANDARD;
+ else
+ search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
+ rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL,
+ CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END,
+ &search_info, false);
+ if (rc == 0) {
+ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) {
+ FIND_FILE_STANDARD_INFO *di;
+ int offset = tcon->ses->server->timeAdj;
+
+ di = (FIND_FILE_STANDARD_INFO *)search_info.srch_entries_start;
+ fi.CreationTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
+ di->CreationDate, di->CreationTime, offset)));
+ fi.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
+ di->LastAccessDate, di->LastAccessTime, offset)));
+ fi.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
+ di->LastWriteDate, di->LastWriteTime, offset)));
+ fi.ChangeTime = fi.LastWriteTime;
+ fi.Attributes = cpu_to_le32(le16_to_cpu(di->Attributes));
+ fi.AllocationSize = cpu_to_le64(le32_to_cpu(di->AllocationSize));
+ fi.EndOfFile = cpu_to_le64(le32_to_cpu(di->DataSize));
+ } else {
+ FILE_FULL_DIRECTORY_INFO *di;
+
+ di = (FILE_FULL_DIRECTORY_INFO *)search_info.srch_entries_start;
+ fi.CreationTime = di->CreationTime;
+ fi.LastAccessTime = di->LastAccessTime;
+ fi.LastWriteTime = di->LastWriteTime;
+ fi.ChangeTime = di->ChangeTime;
+ fi.Attributes = di->ExtFileAttributes;
+ fi.AllocationSize = di->AllocationSize;
+ fi.EndOfFile = di->EndOfFile;
+ fi.EASize = di->EaSize;
+ }
+ fi.NumberOfLinks = cpu_to_le32(1);
+ fi.DeletePending = 0;
+ fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY);
+ cifs_buf_release(search_info.ntwrk_buf_start);
+ } else if (!full_path[0]) {
+ /*
+ * CIFSFindFirst() does not work on root path if the
+ * root path was exported on the server from the top
+ * level path (drive letter).
+ */
+ rc = -EOPNOTSUPP;
+ }
+ }
+
+ /*
+ * If everything failed then fallback to the legacy SMB command
+ * SMB_COM_QUERY_INFORMATION which works with all servers, but
+ * provide just few information.
+ */
+ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && !non_unicode_wildcard) {
rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
cifs_remap(cifs_sb));
data->adjust_tz = true;
+ } else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) {
+ /* Path with non-UNICODE wildcard character cannot exist. */
+ rc = -ENOENT;
}
if (!rc) {
move_cifs_info_to_smb2(&data->fi, &fi);
- data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE;
+ data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE_POINT;
}
#ifdef CONFIG_CIFS_XATTR
/*
+ * For non-symlink WSL reparse points it is required to fetch
+ * EA $LXMOD which contains in its S_DT part the mandatory file type.
+ */
+ if (!rc && data->reparse_point) {
+ struct smb2_file_full_ea_info *ea;
+ u32 next = 0;
+
+ ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
+ do {
+ ea = (void *)((u8 *)ea + next);
+ next = le32_to_cpu(ea->next_entry_offset);
+ } while (next);
+ if (le16_to_cpu(ea->ea_value_length)) {
+ ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
+ ea->ea_name_length + 1 +
+ le16_to_cpu(ea->ea_value_length), 4));
+ ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
+ }
+
+ rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
+ &ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
+ SMB2_WSL_XATTR_MODE_SIZE, cifs_sb);
+ if (rc == SMB2_WSL_XATTR_MODE_SIZE) {
+ ea->next_entry_offset = cpu_to_le32(0);
+ ea->flags = 0;
+ ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
+ ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_MODE_SIZE);
+ memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
+ data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
+ SMB2_WSL_XATTR_MODE_SIZE, 4);
+ rc = 0;
+ } else if (rc >= 0) {
+ /* It is an error if EA $LXMOD has wrong size. */
+ rc = -EINVAL;
+ } else {
+ /*
+ * In all other cases ignore error if fetching
+ * of EA $LXMOD failed. It is needed only for
+ * non-symlink WSL reparse points and wsl_to_fattr()
+ * handle the case when EA is missing.
+ */
+ rc = 0;
+ }
+ }
+
+ /*
* For WSL CHR and BLK reparse points it is required to fetch
* EA $LXDEV which contains major and minor device numbers.
*/
if (!rc && data->reparse_point) {
struct smb2_file_full_ea_info *ea;
+ u32 next = 0;
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
+ do {
+ ea = (void *)((u8 *)ea + next);
+ next = le32_to_cpu(ea->next_entry_offset);
+ } while (next);
+ if (le16_to_cpu(ea->ea_value_length)) {
+ ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
+ ea->ea_name_length + 1 +
+ le16_to_cpu(ea->ea_value_length), 4));
+ ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
+ }
+
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV,
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
SMB2_WSL_XATTR_DEV_SIZE, cifs_sb);
@@ -586,8 +710,8 @@ static int cifs_query_path_info(const unsigned int xid,
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
- data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
- SMB2_WSL_XATTR_DEV_SIZE;
+ data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
+ SMB2_WSL_XATTR_MODE_SIZE, 4);
rc = 0;
} else if (rc >= 0) {
/* It is an error if EA $LXDEV has wrong size. */
@@ -639,6 +763,13 @@ static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
FILE_ALL_INFO fi = {};
+ /*
+ * CIFSSMBQFileInfo() for non-NT servers returns bogus data in
+ * Attributes fields. So do not use this command for non-NT servers.
+ */
+ if (!(tcon->ses->capabilities & CAP_NT_SMBS))
+ return -EOPNOTSUPP;
+
if (cfile->symlink_target) {
data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
if (!data->symlink_target)
@@ -729,6 +860,11 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
info.Attributes = cpu_to_le32(dosattrs);
rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
cifs_sb);
+ if (rc == -EOPNOTSUPP || rc == -EINVAL)
+ rc = SMBSetInformation(xid, tcon, full_path,
+ info.Attributes,
+ 0 /* do not change write time */,
+ cifs_sb->local_nls, cifs_sb);
if (rc == 0)
cifsInode->cifsAttrs = dosattrs;
}
@@ -761,6 +897,9 @@ static void
cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
{
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
+
+ lockdep_assert_held(&cinode->open_file_lock);
+
cfile->fid.netfid = fid->netfid;
cifs_set_oplock_level(cinode, oplock);
cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
@@ -809,27 +948,68 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifsFileInfo *open_file;
+ FILE_BASIC_INFO new_buf;
+ struct cifs_open_info_data query_data;
+ __le64 write_time = buf->LastWriteTime;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon;
/* if the file is already open for write, just use that fileid */
- open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
+ open_file = find_writable_file(cinode, FIND_FSUID_ONLY);
+
if (open_file) {
fid.netfid = open_file->fid.netfid;
netpid = open_file->pid;
tcon = tlink_tcon(open_file->tlink);
- goto set_via_filehandle;
+ } else {
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink)) {
+ rc = PTR_ERR(tlink);
+ tlink = NULL;
+ goto out;
+ }
+ tcon = tlink_tcon(tlink);
}
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink)) {
- rc = PTR_ERR(tlink);
- tlink = NULL;
- goto out;
+ /*
+ * Non-NT servers interprets zero time value in SMB_SET_FILE_BASIC_INFO
+ * over TRANS2_SET_FILE_INFORMATION as a valid time value. NT servers
+ * interprets zero time value as do not change existing value on server.
+ * API of ->set_file_info() callback expects that zero time value has
+ * the NT meaning - do not change. Therefore if server is non-NT and
+ * some time values in "buf" are zero, then fetch missing time values.
+ */
+ if (!(tcon->ses->capabilities & CAP_NT_SMBS) &&
+ (!buf->CreationTime || !buf->LastAccessTime ||
+ !buf->LastWriteTime || !buf->ChangeTime)) {
+ rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data);
+ if (rc) {
+ if (open_file) {
+ cifsFileInfo_put(open_file);
+ open_file = NULL;
+ }
+ goto out;
+ }
+ /*
+ * Original write_time from buf->LastWriteTime is preserved
+ * as SMBSetInformation() interprets zero as do not change.
+ */
+ new_buf = *buf;
+ buf = &new_buf;
+ if (!buf->CreationTime)
+ buf->CreationTime = query_data.fi.CreationTime;
+ if (!buf->LastAccessTime)
+ buf->LastAccessTime = query_data.fi.LastAccessTime;
+ if (!buf->LastWriteTime)
+ buf->LastWriteTime = query_data.fi.LastWriteTime;
+ if (!buf->ChangeTime)
+ buf->ChangeTime = query_data.fi.ChangeTime;
}
- tcon = tlink_tcon(tlink);
+
+ if (open_file)
+ goto set_via_filehandle;
rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
cifs_sb);
@@ -844,14 +1024,51 @@ smb_set_file_info(struct inode *inode, const char *full_path,
.tcon = tcon,
.cifs_sb = cifs_sb,
.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
- .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
+ .create_options = cifs_create_options(cifs_sb, 0),
.disposition = FILE_OPEN,
.path = full_path,
.fid = &fid,
};
- cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
- rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (S_ISDIR(inode->i_mode) && !(tcon->ses->capabilities & CAP_NT_SMBS)) {
+ /* Opening directory path is not possible on non-NT servers. */
+ rc = -EOPNOTSUPP;
+ } else {
+ /*
+ * Use cifs_open_file() instead of CIFS_open() as the
+ * cifs_open_file() selects the correct function which
+ * works also on non-NT servers.
+ */
+ rc = cifs_open_file(xid, &oparms, &oplock, NULL);
+ /*
+ * Opening path for writing on non-NT servers is not
+ * possible when the read-only attribute is already set.
+ * Non-NT server in this case returns -EACCES. For those
+ * servers the only possible way how to clear the read-only
+ * bit is via SMB_COM_SETATTR command.
+ */
+ if (rc == -EACCES &&
+ (cinode->cifsAttrs & ATTR_READONLY) &&
+ le32_to_cpu(buf->Attributes) != 0 && /* 0 = do not change attrs */
+ !(le32_to_cpu(buf->Attributes) & ATTR_READONLY) &&
+ !(tcon->ses->capabilities & CAP_NT_SMBS))
+ rc = -EOPNOTSUPP;
+ }
+
+ /* Fallback to SMB_COM_SETATTR command when absolutely needed. */
+ if (rc == -EOPNOTSUPP) {
+ cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n");
+ rc = SMBSetInformation(xid, tcon, full_path,
+ buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs),
+ write_time,
+ cifs_sb->local_nls, cifs_sb);
+ if (rc == 0)
+ cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+ else
+ rc = -EACCES;
+ goto out;
+ }
+
if (rc != 0) {
if (rc == -EIO)
rc = -EINVAL;
@@ -859,6 +1076,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
}
netpid = current->tgid;
+ cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for attrs/times not supported by this server\n");
set_via_filehandle:
rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
@@ -869,6 +1087,21 @@ set_via_filehandle:
CIFSSMBClose(xid, tcon, fid.netfid);
else
cifsFileInfo_put(open_file);
+
+ /*
+ * Setting the read-only bit is not honored on non-NT servers when done
+ * via open-semantics. So for setting it, use SMB_COM_SETATTR command.
+ * This command works only after the file is closed, so use it only when
+ * operation was called without the filehandle.
+ */
+ if (open_file == NULL &&
+ !(tcon->ses->capabilities & CAP_NT_SMBS) &&
+ le32_to_cpu(buf->Attributes) & ATTR_READONLY) {
+ SMBSetInformation(xid, tcon, full_path,
+ buf->Attributes,
+ 0 /* do not change write time */,
+ cifs_sb->local_nls, cifs_sb);
+ }
out:
if (tlink != NULL)
cifs_put_tlink(tlink);
@@ -912,12 +1145,16 @@ cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
return CIFSFindClose(xid, tcon, fid->netfid);
}
-static int
-cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
- __u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode)
+static int cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
+ __u64 volatile_fid, __u16 net_fid,
+ struct cifsInodeInfo *cinode, unsigned int oplock)
{
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
+ __u8 op;
+
+ op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE));
return CIFSSMBLock(0, tcon, net_fid, current->tgid, 0, 0, 0, 0,
- LOCKING_ANDX_OPLOCK_RELEASE, false, CIFS_CACHE_READ(cinode) ? 1 : 0);
+ LOCKING_ANDX_OPLOCK_RELEASE, false, op);
}
static int
@@ -1047,7 +1284,8 @@ cifs_make_node(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, umode_t mode, dev_t dev)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct inode *newinode = NULL;
int rc;
@@ -1063,7 +1301,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
.mtime = NO_CHANGE_64,
.device = dev,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
args.gid = current_fsgid();
} else {
@@ -1082,17 +1320,26 @@ cifs_make_node(unsigned int xid, struct inode *inode,
if (rc == 0)
d_instantiate(dentry, newinode);
return rc;
+ } else if (sbflags & CIFS_MOUNT_UNX_EMUL) {
+ /*
+ * Check if mounted with mount parm 'sfu' mount parm.
+ * SFU emulation should work with all servers
+ * and was used by default in earlier versions of Windows.
+ */
+ return cifs_sfu_make_node(xid, inode, dentry, tcon,
+ full_path, mode, dev);
+ } else if (CIFS_REPARSE_SUPPORT(tcon)) {
+ /*
+ * mknod via reparse points requires server support for
+ * storing reparse points, which is available since
+ * Windows 2000, but was not widely used until release
+ * of Windows Server 2012 by the Windows NFS server.
+ */
+ return mknod_reparse(xid, inode, dentry, tcon,
+ full_path, mode, dev);
+ } else {
+ return -EOPNOTSUPP;
}
- /*
- * Check if mounted with mount parm 'sfu' mount parm.
- * SFU emulation should work with all servers, but only
- * supports block and char device, socket & fifo,
- * and was used by default in earlier versions of Windows
- */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
- return -EPERM;
- return cifs_sfu_make_node(xid, inode, dentry, tcon,
- full_path, mode, dev);
}
static bool
@@ -1137,7 +1384,7 @@ cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
}
struct smb_version_operations smb1_operations = {
- .send_cancel = send_nt_cancel,
+ .send_cancel = cifs_send_cancel,
.compare_fids = cifs_compare_fids,
.setup_request = cifs_setup_request,
.setup_async_request = cifs_setup_async_request,
@@ -1161,8 +1408,8 @@ struct smb_version_operations smb1_operations = {
.check_trans2 = cifs_check_trans2,
.need_neg = cifs_need_neg,
.negotiate = cifs_negotiate,
- .negotiate_wsize = cifs_negotiate_wsize,
- .negotiate_rsize = cifs_negotiate_rsize,
+ .negotiate_wsize = smb1_negotiate_wsize,
+ .negotiate_rsize = smb1_negotiate_rsize,
.sess_setup = CIFS_SessSetup,
.logoff = CIFSSMBLogoff,
.tree_connect = CIFSTCon,
@@ -1189,6 +1436,7 @@ struct smb_version_operations smb1_operations = {
.create_hardlink = CIFSCreateHardLink,
.query_symlink = cifs_query_symlink,
.get_reparse_point_buffer = cifs_get_reparse_point_buffer,
+ .create_reparse_inode = cifs_create_reparse_inode,
.open = cifs_open_file,
.set_fid = cifs_set_fid,
.close = cifs_close_file,
@@ -1230,7 +1478,6 @@ struct smb_version_values smb1_values = {
.exclusive_lock_type = 0,
.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
.unlock_lock_type = 0,
- .header_preamble_size = 4,
.header_size = sizeof(struct smb_hdr),
.max_header_size = MAX_CIFS_HDR_SIZE,
.read_rsp_size = sizeof(READ_RSP),
diff --git a/fs/smb/client/smb1pdu.h b/fs/smb/client/smb1pdu.h
new file mode 100644
index 000000000000..7584e94d9b2b
--- /dev/null
+++ b/fs/smb/client/smb1pdu.h
@@ -0,0 +1,2345 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2002,2009
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ */
+
+#ifndef _SMB1PDU_H
+#define _SMB1PDU_H
+
+#include "../common/smb1pdu.h"
+
+#define CIFS_PROT 0
+#define POSIX_PROT (CIFS_PROT+1)
+#define BAD_PROT 0xFFFF
+
+/* SMB command codes:
+ * See MS-CIFS 2.2.2.1
+ * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses
+ * (ie which include no useful data other than the SMB error code itself).
+ * This can allow us to avoid response buffer allocations and copy in some cases
+ */
+#define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */
+#define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */
+#define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */
+#define SMB_COM_FLUSH 0x05 /* triv req/rsp */
+#define SMB_COM_DELETE 0x06 /* trivial response */
+#define SMB_COM_RENAME 0x07 /* trivial response */
+#define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */
+#define SMB_COM_SETATTR 0x09 /* trivial response */
+#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
+#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_ECHO 0x2B /* echo request */
+#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
+#define SMB_COM_READ_ANDX 0x2E
+#define SMB_COM_WRITE_ANDX 0x2F
+#define SMB_COM_TRANSACTION2 0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_FIND_CLOSE2 0x34 /* trivial response */
+#define SMB_COM_TREE_DISCONNECT 0x71 /* trivial response */
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SESSION_SETUP_ANDX 0x73
+#define SMB_COM_LOGOFF_ANDX 0x74 /* trivial response */
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+#define SMB_COM_NT_TRANSACT 0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX 0xA2
+#define SMB_COM_NT_CANCEL 0xA4 /* no response */
+#define SMB_COM_NT_RENAME 0xA5 /* trivial response */
+
+/* Transact2 subcommand codes */
+#define TRANS2_OPEN 0x00
+#define TRANS2_FIND_FIRST 0x01
+#define TRANS2_FIND_NEXT 0x02
+#define TRANS2_QUERY_FS_INFORMATION 0x03
+#define TRANS2_SET_FS_INFORMATION 0x04
+#define TRANS2_QUERY_PATH_INFORMATION 0x05
+#define TRANS2_SET_PATH_INFORMATION 0x06
+#define TRANS2_QUERY_FILE_INFORMATION 0x07
+#define TRANS2_SET_FILE_INFORMATION 0x08
+#define TRANS2_GET_DFS_REFERRAL 0x10
+#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
+
+/* SMB Transact (Named Pipe) subcommand codes */
+#define TRANS_SET_NMPIPE_STATE 0x0001
+#define TRANS_RAW_READ_NMPIPE 0x0011
+#define TRANS_QUERY_NMPIPE_STATE 0x0021
+#define TRANS_QUERY_NMPIPE_INFO 0x0022
+#define TRANS_PEEK_NMPIPE 0x0023
+#define TRANS_TRANSACT_NMPIPE 0x0026
+#define TRANS_RAW_WRITE_NMPIPE 0x0031
+#define TRANS_READ_NMPIPE 0x0036
+#define TRANS_WRITE_NMPIPE 0x0037
+#define TRANS_WAIT_NMPIPE 0x0053
+#define TRANS_CALL_NMPIPE 0x0054
+
+/* NT Transact subcommand codes */
+#define NT_TRANSACT_CREATE 0x01
+#define NT_TRANSACT_IOCTL 0x02
+#define NT_TRANSACT_SET_SECURITY_DESC 0x03
+#define NT_TRANSACT_NOTIFY_CHANGE 0x04
+#define NT_TRANSACT_RENAME 0x05
+#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06
+#define NT_TRANSACT_GET_USER_QUOTA 0x07
+#define NT_TRANSACT_SET_USER_QUOTA 0x08
+
+/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
+/* among the requests (NTCreateX response is bigger with wct of 34) */
+#define MAX_CIFS_HDR_SIZE 0x54 /* 32 hdr + (2*24 wct) + 2 bct + 2 pad */
+#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
+
+/* internal cifs vfs structures */
+/*****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+/*
+ * Starting value for maximum SMB size negotiation
+ */
+#define CIFS_MAX_MSGSIZE (4*4096)
+
+/*
+ * Size of encrypted user password in bytes
+ */
+#define CIFS_ENCPWD_SIZE (16)
+
+/*
+ * Size of the crypto key returned on the negotiate SMB in bytes
+ */
+#define CIFS_CRYPTO_KEY_SIZE (8)
+
+/*
+ * Size of the ntlm client response
+ */
+#define CIFS_AUTH_RESP_SIZE (24)
+
+/*
+ * Size of the session key (crypto key encrypted with the password
+ */
+#define CIFS_SESS_KEY_SIZE (16)
+
+#define CIFS_SERVER_CHALLENGE_SIZE (8)
+#define CIFS_HMAC_MD5_HASH_SIZE (16)
+#define CIFS_CPHTXT_SIZE (16)
+#define CIFS_NTHASH_SIZE (16)
+
+/*
+ * Maximum user name length
+ */
+#define CIFS_UNLEN (20)
+
+/*
+ * Flags on SMB open
+ */
+#define SMBOPEN_WRITE_THROUGH 0x4000
+#define SMBOPEN_DENY_ALL 0x0010
+#define SMBOPEN_DENY_WRITE 0x0020
+#define SMBOPEN_DENY_READ 0x0030
+#define SMBOPEN_DENY_NONE 0x0040
+#define SMBOPEN_READ 0x0000
+#define SMBOPEN_WRITE 0x0001
+#define SMBOPEN_READWRITE 0x0002
+#define SMBOPEN_EXECUTE 0x0003
+
+#define SMBOPEN_OCREATE 0x0010
+#define SMBOPEN_OTRUNC 0x0002
+#define SMBOPEN_OAPPEND 0x0001
+
+/*
+ * SMB flag definitions
+ * See MS-CIFS 2.2.3.1
+ */
+#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */
+#define SMBFLG_RCV_POSTED 0x02 /* obsolete */
+#define SMBFLG_RSVD 0x04
+#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off
+ implies case sensitive file handling request) */
+#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */
+#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */
+#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */
+#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
+
+/*
+ * SMB flag2 definitions
+ * See MS-CIFS 2.2.3.1
+ * MS-SMB 2.2.3.1
+ */
+#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3)
+ path names in response */
+#define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
+#define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
+#define SMBFLG2_COMPRESSED (8)
+#define SMBFLG2_SECURITY_SIGNATURE_REQUIRED (0x10)
+#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
+#define SMBFLG2_REPARSE_PATH (0x400)
+#define SMBFLG2_EXT_SEC cpu_to_le16(0x800)
+#define SMBFLG2_DFS cpu_to_le16(0x1000)
+#define SMBFLG2_PAGING_IO cpu_to_le16(0x2000)
+#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000)
+#define SMBFLG2_UNICODE cpu_to_le16(0x8000)
+
+/* Combinations of file access permission bits */
+#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \
+ | FILE_READ_ATTRIBUTES \
+ | FILE_WRITE_ATTRIBUTES \
+ | DELETE | READ_CONTROL | WRITE_DAC \
+ | WRITE_OWNER | SYNCHRONIZE)
+#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
+ | FILE_READ_EA | FILE_WRITE_EA \
+ | FILE_READ_ATTRIBUTES \
+ | FILE_WRITE_ATTRIBUTES \
+ | DELETE | READ_CONTROL | WRITE_DAC \
+ | WRITE_OWNER | SYNCHRONIZE)
+
+/*
+ * Invalid readdir handle
+ */
+#define CIFS_NO_HANDLE 0xFFFF
+
+#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
+
+/* IPC$ in ASCII */
+#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
+
+/* IPC$ in Unicode */
+#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00"
+
+/* Unicode Null terminate 2 bytes of 0 */
+#define UNICODE_NULL "\x00\x00"
+#define ASCII_NULL 0x00
+
+/*
+ * Server type values (returned on EnumServer API
+ */
+#define CIFS_SV_TYPE_DC 0x00000008
+#define CIFS_SV_TYPE_BACKDC 0x00000010
+
+/*
+ * Alias type flags (From EnumAlias API call
+ */
+#define CIFS_ALIAS_TYPE_FILE 0x0001
+#define CIFS_SHARE_TYPE_FILE 0x0000
+
+/*
+ * File Attribute flags
+ */
+#define ATTR_READONLY 0x0001 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_HIDDEN 0x0002 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_SYSTEM 0x0004 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_VOLUME 0x0008
+#define ATTR_DIRECTORY 0x0010 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_ARCHIVE 0x0020 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_DEVICE 0x0040
+#define ATTR_NORMAL 0x0080 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_TEMPORARY 0x0100 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_SPARSE 0x0200 /* See MS-SMB 2.2.1.2.1 */
+#define ATTR_REPARSE_POINT 0x0400 /* See MS-SMB 2.2.1.2.1 */
+#define ATTR_COMPRESSED 0x0800 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_OFFLINE 0x1000 /* See MS-SMB 2.2.1.2.1
+ ie file not immediately available -
+ on offline storage */
+#define ATTR_NOT_CONTENT_INDEXED 0x2000 /* See MS-SMB 2.2.1.2.1 */
+#define ATTR_ENCRYPTED 0x4000 /* See MS-SMB 2.2.1.2.1 */
+#define ATTR_POSIX_SEMANTICS 0x0100000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_BACKUP_SEMANTICS 0x0200000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_DELETE_ON_CLOSE 0x0400000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_SEQUENTIAL_SCAN 0x0800000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_RANDOM_ACCESS 0x1000000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_NO_BUFFERING 0x2000000 /* See MS-CIFS 2.2.1.2.3 */
+#define ATTR_WRITE_THROUGH 0x8000000 /* See MS-CIFS 2.2.1.2.3 */
+
+/* ShareAccess flags */
+#define FILE_NO_SHARE 0x00000000
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_ALL 0x00000007
+
+/* CreateDisposition flags, similar to CreateAction as well */
+#define FILE_SUPERSEDE 0x00000000
+#define FILE_OPEN 0x00000001
+#define FILE_CREATE 0x00000002
+#define FILE_OPEN_IF 0x00000003
+#define FILE_OVERWRITE 0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+
+/* CreateOptions */
+#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
+#define CREATE_WRITE_THROUGH 0x00000002
+#define CREATE_SEQUENTIAL 0x00000004
+#define CREATE_NO_BUFFER 0x00000008 /* should not buffer on srv */
+#define CREATE_SYNC_ALERT 0x00000010 /* MBZ */
+#define CREATE_ASYNC_ALERT 0x00000020 /* MBZ */
+#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
+#define CREATE_TREE_CONNECTION 0x00000080 /* should be zero */
+#define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */
+#define CREATE_NO_EA_KNOWLEDGE 0x00000200
+#define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete
+ "open for recovery" flag should
+ be zero in any case */
+#define CREATE_OPEN_FOR_RECOVERY 0x00000400
+#define CREATE_RANDOM_ACCESS 0x00000800
+#define CREATE_DELETE_ON_CLOSE 0x00001000
+#define CREATE_OPEN_BY_ID 0x00002000
+#define CREATE_OPEN_BACKUP_INTENT 0x00004000
+#define CREATE_NO_COMPRESSION 0x00008000
+#define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */
+#define OPEN_REPARSE_POINT 0x00200000
+#define OPEN_NO_RECALL 0x00400000
+#define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */
+#define CREATE_OPTIONS_MASK 0x007FFFFF
+#define CREATE_OPTION_READONLY 0x10000000
+#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
+
+/* ImpersonationLevel flags */
+#define SECURITY_ANONYMOUS 0
+#define SECURITY_IDENTIFICATION 1
+#define SECURITY_IMPERSONATION 2
+#define SECURITY_DELEGATION 3
+
+/* SecurityFlags */
+#define SECURITY_CONTEXT_TRACKING 0x01
+#define SECURITY_EFFECTIVE_ONLY 0x02
+
+/*
+ * Default PID value, used in all SMBs where the PID is not important
+ */
+#define CIFS_DFT_PID 0x1234
+
+/*
+ * We use the same routine for Copy and Move SMBs. This flag is used to
+ * distinguish
+ */
+#define CIFS_COPY_OP 1
+#define CIFS_RENAME_OP 2
+
+/*
+ * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
+ * No longer as important, now that TCP names are more commonly used to
+ * resolve hosts.
+ */
+#define CNLEN 15
+
+/*
+ * Share Name Length (SNLEN)
+ * Note: This length was limited by the SMB used to get
+ * the Share info. NetShareEnum only returned 13
+ * chars, including the null termination.
+ * This was removed because it no longer is limiting.
+ */
+
+/*
+ * Comment Length
+ */
+#define MAXCOMMENTLEN 40
+
+/*
+ * The OS/2 maximum path name
+ */
+#define MAX_PATHCONF 256
+
+/*
+ * SMB frame definitions (following must be packed structs)
+ * See the SNIA CIFS Specification for details.
+ *
+ * The Naming convention is the lower case version of the
+ * smb command code name for the struct and this is typedef to the
+ * uppercase version of the same name with the prefix SMB_ removed
+ * for brevity. Although typedefs are not commonly used for
+ * structure definitions in the Linux kernel, their use in the
+ * CIFS standards document, which this code is based on, may
+ * make this one of the cases where typedefs for structures make
+ * sense to improve readability for readers of the standards doc.
+ * Typedefs can always be removed later if they are too distracting
+ * and they are only used for the CIFSs PDUs themselves, not
+ * internal cifs vfs structures
+ *
+ */
+
+#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
+
+#define READ_RAW_ENABLE 1
+#define WRITE_RAW_ENABLE 2
+#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
+#define SMB1_CLIENT_GUID_SIZE (16)
+
+/* See MS-CIFS 2.2.4.52.2 */
+typedef struct smb_negotiate_rsp {
+ struct smb_hdr hdr; /* wct = 17 */
+ __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
+ __u8 SecurityMode;
+ __le16 MaxMpxCount;
+ __le16 MaxNumberVcs;
+ __le32 MaxBufferSize;
+ __le32 MaxRawSize;
+ __le32 SessionKey;
+ __le32 Capabilities; /* see below */
+ __le32 SystemTimeLow;
+ __le32 SystemTimeHigh;
+ __le16 ServerTimeZone;
+ __u8 EncryptionKeyLength;
+ __u16 ByteCount;
+ union {
+ /* cap extended security off */
+ DECLARE_FLEX_ARRAY(unsigned char, EncryptionKey);
+ /* followed by Domain name - if extended security is off */
+ /* followed by 16 bytes of server GUID */
+ /* then security blob if cap_extended_security negotiated */
+ struct {
+ unsigned char GUID[SMB1_CLIENT_GUID_SIZE];
+ unsigned char SecurityBlob[];
+ } __packed extended_response;
+ } __packed u;
+} __packed SMB_NEGOTIATE_RSP;
+
+/* SecurityMode bits */
+#define SECMODE_USER 0x01 /* off indicates share level security */
+#define SECMODE_PW_ENCRYPT 0x02
+#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */
+#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */
+
+/* Negotiate response Capabilities */
+#define CAP_RAW_MODE 0x00000001
+#define CAP_MPX_MODE 0x00000002
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */
+#define CAP_RPC_REMOTE_APIS 0x00000020
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_LOCK_AND_READ 0x00000100
+#define CAP_NT_FIND 0x00000200
+#define CAP_DFS 0x00001000
+#define CAP_INFOLEVEL_PASSTHRU 0x00002000
+#define CAP_LARGE_READ_X 0x00004000
+#define CAP_LARGE_WRITE_X 0x00008000
+#define CAP_LWIO 0x00010000 /* support fctl_srv_req_resume_key */
+#define CAP_UNIX 0x00800000
+#define CAP_COMPRESSED_DATA 0x02000000
+#define CAP_DYNAMIC_REAUTH 0x20000000
+#define CAP_PERSISTENT_HANDLES 0x40000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+typedef union smb_com_session_setup_andx {
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 MaxBufferSize;
+ __le16 MaxMpxCount;
+ __le16 VcNumber;
+ __le32 SessionKey;
+ __le16 SecurityBlobLength;
+ __u32 Reserved;
+ __le32 Capabilities; /* see below */
+ __le16 ByteCount;
+ unsigned char SecurityBlob[]; /* followed by */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } __packed req; /* NTLM request format (with
+ extended security */
+
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 13 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 MaxBufferSize;
+ __le16 MaxMpxCount;
+ __le16 VcNumber;
+ __le32 SessionKey;
+ __le16 CaseInsensitivePasswordLength; /* ASCII password len */
+ __le16 CaseSensitivePasswordLength; /* Unicode password length*/
+ __u32 Reserved; /* see below */
+ __le32 Capabilities;
+ __le16 ByteCount;
+ unsigned char CaseInsensitivePassword[]; /* followed by: */
+ /* unsigned char * CaseSensitivePassword; */
+ /* STRING AccountName */
+ /* STRING PrimaryDomain */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } __packed req_no_secext; /* NTLM request format (without
+ extended security */
+
+ struct { /* default (NTLM) response format */
+ struct smb_hdr hdr; /* wct = 4 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 Action; /* see below */
+ __le16 SecurityBlobLength;
+ __u16 ByteCount;
+ unsigned char SecurityBlob[]; /* followed by */
+/* unsigned char * NativeOS; */
+/* unsigned char * NativeLanMan; */
+/* unsigned char * PrimaryDomain; */
+ } __packed resp; /* NTLM response
+ (with or without extended sec) */
+
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 10 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 MaxBufferSize;
+ __le16 MaxMpxCount;
+ __le16 VcNumber;
+ __le32 SessionKey;
+ __le16 PasswordLength;
+ __u32 Reserved; /* encrypt key len and offset */
+ __le16 ByteCount;
+ unsigned char AccountPassword[]; /* followed by */
+ /* STRING AccountName */
+ /* STRING PrimaryDomain */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } __packed old_req; /* pre-NTLM (LANMAN2.1) req format */
+
+ struct { /* default (NTLM) response format */
+ struct smb_hdr hdr; /* wct = 3 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 Action; /* see below */
+ __u16 ByteCount;
+ unsigned char NativeOS[]; /* followed by */
+/* unsigned char * NativeLanMan; */
+/* unsigned char * PrimaryDomain; */
+ } __packed old_resp; /* pre-NTLM (LANMAN2.1) response */
+} __packed SESSION_SETUP_ANDX;
+
+/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
+
+#define NTLMSSP_SERVER_TYPE 1
+#define NTLMSSP_DOMAIN_TYPE 2
+#define NTLMSSP_FQ_DOMAIN_TYPE 3
+#define NTLMSSP_DNS_DOMAIN_TYPE 4
+#define NTLMSSP_DNS_PARENT_TYPE 5
+
+struct ntlmssp2_name {
+ __le16 type;
+ __le16 length;
+ __u8 data[];
+} __packed;
+
+struct ntlmv2_resp {
+ union {
+ char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+ struct {
+ __u8 reserved[8];
+ __u8 key[CIFS_SERVER_CHALLENGE_SIZE];
+ } __packed challenge;
+ } __packed;
+ __le32 blob_signature;
+ __u32 reserved;
+ __le64 time;
+ __u64 client_chal; /* random */
+ __u32 reserved2;
+ /* array of name entries could follow ending in minimum 4 byte struct */
+} __packed;
+
+
+#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
+
+
+/*
+ * Capabilities bits (for NTLM SessSetup request)
+ * See MS-CIFS 2.2.4.52.2
+ * MS-SMB 2.2.4.5.2.1
+ */
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_NT_FIND 0x00000200 /* reserved should be zero
+ (because NT_SMBs implies the same thing?) */
+#define CAP_BULK_TRANSFER 0x00000400
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+/* Action bits */
+#define GUEST_LOGIN 1
+
+typedef struct smb_com_tconx_req {
+ struct smb_hdr hdr; /* wct = 4 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 Flags; /* see below */
+ __le16 PasswordLength;
+ __le16 ByteCount;
+ unsigned char Password[]; /* followed by */
+/* STRING Path *//* \\server\share name */
+ /* STRING Service */
+} __packed TCONX_REQ;
+
+typedef struct smb_com_tconx_rsp {
+ struct smb_hdr hdr; /* wct = 3 , not extended response */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 OptionalSupport; /* see below */
+ __u16 ByteCount;
+ unsigned char Service[]; /* always ASCII, not Unicode */
+ /* STRING NativeFileSystem */
+} __packed TCONX_RSP;
+
+typedef struct smb_com_tconx_rsp_ext {
+ struct smb_hdr hdr; /* wct = 7, extended response */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 OptionalSupport; /* see below */
+ __le32 MaximalShareAccessRights;
+ __le32 GuestMaximalShareAccessRights;
+ __u16 ByteCount;
+ unsigned char Service[]; /* always ASCII, not Unicode */
+ /* STRING NativeFileSystem */
+} __packed TCONX_RSP_EXT;
+
+
+/* tree connect Flags */
+#define DISCONNECT_TID 0x0001
+#define TCON_EXTENDED_SIGNATURES 0x0004
+#define TCON_EXTENDED_SECINFO 0x0008
+
+/* OptionalSupport bits */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits
+ (exclusive searches supported) */
+#define SMB_SHARE_IS_IN_DFS 0x0002
+#define SMB_CSC_MASK 0x000C
+/* CSC flags defined as follows */
+#define SMB_CSC_CACHE_MANUAL_REINT 0x0000
+#define SMB_CSC_CACHE_AUTO_REINT 0x0004
+#define SMB_CSC_CACHE_VDO 0x0008
+#define SMB_CSC_NO_CACHING 0x000C
+#define SMB_UNIQUE_FILE_NAME 0x0010
+#define SMB_EXTENDED_SIGNATURES 0x0020
+
+/* services
+ *
+ * A: ie disk
+ * LPT1: ie printer
+ * IPC ie named pipe
+ * COMM
+ * ????? ie any type
+ *
+ */
+
+typedef struct smb_com_echo_req {
+ struct smb_hdr hdr;
+ __le16 EchoCount;
+ __le16 ByteCount;
+ char Data[];
+} __packed ECHO_REQ;
+
+typedef struct smb_com_echo_rsp {
+ struct smb_hdr hdr;
+ __le16 SequenceNumber;
+ __le16 ByteCount;
+ char Data[];
+} __packed ECHO_RSP;
+
+typedef struct smb_com_logoff_andx_req {
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 ByteCount;
+} __packed LOGOFF_ANDX_REQ;
+
+typedef struct smb_com_logoff_andx_rsp {
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 ByteCount;
+} __packed LOGOFF_ANDX_RSP;
+
+typedef union smb_com_tree_disconnect { /* as an alternative can use flag on
+ tree_connect PDU to effect disconnect */
+ /* tdis is probably simplest SMB PDU */
+ struct {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bcc = 0 */
+ } __packed req;
+ struct {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bcc = 0 */
+ } __packed resp;
+} __packed TREE_DISCONNECT;
+
+typedef struct smb_com_close_req {
+ struct smb_hdr hdr; /* wct = 3 */
+ __u16 FileID;
+ __u32 LastWriteTime; /* should be zero or -1 */
+ __u16 ByteCount; /* 0 */
+} __packed CLOSE_REQ;
+
+typedef struct smb_com_close_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed CLOSE_RSP;
+
+typedef struct smb_com_flush_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 FileID;
+ __u16 ByteCount; /* 0 */
+} __packed FLUSH_REQ;
+
+typedef struct smb_com_findclose_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 FileID;
+ __u16 ByteCount; /* 0 */
+} __packed FINDCLOSE_REQ;
+
+/* OpenFlags */
+#define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */
+#define REQ_OPLOCK 0x00000002
+#define REQ_BATCHOPLOCK 0x00000004
+#define REQ_OPENDIRONLY 0x00000008
+#define REQ_EXTENDED_INFO 0x00000010
+
+/* File type */
+#define DISK_TYPE 0x0000
+#define BYTE_PIPE_TYPE 0x0001
+#define MESSAGE_PIPE_TYPE 0x0002
+#define PRINTER_TYPE 0x0003
+#define COMM_DEV_TYPE 0x0004
+#define UNKNOWN_TYPE 0xFFFF
+
+/* Device Type or File Status Flags */
+#define NO_EAS 0x0001
+#define NO_SUBSTREAMS 0x0002
+#define NO_REPARSETAG 0x0004
+/* following flags can apply if pipe */
+#define ICOUNT_MASK 0x00FF
+#define PIPE_READ_MODE 0x0100
+#define NAMED_PIPE_TYPE 0x0400
+#define PIPE_END_POINT 0x4000
+#define BLOCKING_NAMED_PIPE 0x8000
+
+typedef struct smb_com_open_req { /* also handles create */
+ struct smb_hdr hdr; /* wct = 24 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u8 Reserved; /* Must Be Zero */
+ __le16 NameLength;
+ __le32 OpenFlags;
+ __u32 RootDirectoryFid;
+ __le32 DesiredAccess;
+ __le64 AllocationSize;
+ __le32 FileAttributes;
+ __le32 ShareAccess;
+ __le32 CreateDisposition;
+ __le32 CreateOptions;
+ __le32 ImpersonationLevel;
+ __u8 SecurityFlags;
+ __le16 ByteCount;
+ char fileName[];
+} __packed OPEN_REQ;
+
+/* open response: oplock levels */
+#define OPLOCK_NONE 0
+#define OPLOCK_EXCLUSIVE 1
+#define OPLOCK_BATCH 2
+#define OPLOCK_READ 3 /* level 2 oplock */
+
+/* open response for CreateAction shifted left */
+#define CIFS_CREATE_ACTION 0x20000 /* file created */
+
+typedef struct smb_com_open_rsp {
+ struct smb_hdr hdr; /* wct = 34 BB */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u8 OplockLevel;
+ __u16 Fid;
+ __le32 CreateAction;
+ struct_group_attr(common_attributes, __packed,
+ __le64 CreationTime;
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le32 FileAttributes;
+ );
+ __le64 AllocationSize;
+ __le64 EndOfFile;
+ __le16 FileType;
+ __le16 DeviceState;
+ __u8 DirectoryFlag;
+ __u16 ByteCount; /* bct = 0 */
+} __packed OPEN_RSP;
+
+typedef struct smb_com_open_rsp_ext {
+ struct smb_hdr hdr; /* wct = 42 but meaningless due to MS bug? */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u8 OplockLevel;
+ __u16 Fid;
+ __le32 CreateAction;
+ __le64 CreationTime;
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le32 FileAttributes;
+ __le64 AllocationSize;
+ __le64 EndOfFile;
+ __le16 FileType;
+ __le16 DeviceState;
+ __u8 DirectoryFlag;
+ __u8 VolumeGUID[16];
+ __u64 FileId; /* note no endian conversion - is opaque UniqueID */
+ __le32 MaximalAccessRights;
+ __le32 GuestMaximalAccessRights;
+ __u16 ByteCount; /* bct = 0 */
+} __packed OPEN_RSP_EXT;
+
+
+/* format of legacy open request */
+typedef struct smb_com_openx_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 OpenFlags;
+ __le16 Mode;
+ __le16 Sattr; /* search attributes */
+ __le16 FileAttributes; /* dos attrs */
+ __le32 CreateTime; /* os2 format */
+ __le16 OpenFunction;
+ __le32 EndOfFile;
+ __le32 Timeout;
+ __le32 Reserved;
+ __le16 ByteCount; /* file name follows */
+ char fileName[];
+} __packed OPENX_REQ;
+
+typedef struct smb_com_openx_rsp {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le16 FileAttributes;
+ __le32 LastWriteTime; /* os2 format */
+ __le32 EndOfFile;
+ __le16 Access;
+ __le16 FileType;
+ __le16 IPCState;
+ __le16 Action;
+ __u32 FileId;
+ __u16 Reserved;
+ __u16 ByteCount;
+} __packed OPENX_RSP;
+
+/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */
+
+/* Legacy write request for older servers */
+typedef struct smb_com_writex_req {
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __u32 Reserved; /* Timeout */
+ __le16 WriteMode; /* 1 = write through */
+ __le16 Remaining;
+ __le16 Reserved2;
+ __le16 DataLengthLow;
+ __le16 DataOffset;
+ __le16 ByteCount;
+ __u8 Pad; /* BB check for whether padded to DWORD
+ boundary and optimum performance here */
+ char Data[];
+} __packed WRITEX_REQ;
+
+typedef struct smb_com_write_req {
+ struct smb_hdr hdr; /* wct = 14 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __u32 Reserved;
+ __le16 WriteMode;
+ __le16 Remaining;
+ __le16 DataLengthHigh;
+ __le16 DataLengthLow;
+ __le16 DataOffset;
+ __le32 OffsetHigh;
+ __le16 ByteCount;
+ __u8 Pad; /* BB check for whether padded to DWORD
+ boundary and optimum performance here */
+ char Data[];
+} __packed WRITE_REQ;
+
+typedef struct smb_com_write_rsp {
+ struct smb_hdr hdr; /* wct = 6 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 Count;
+ __le16 Remaining;
+ __le16 CountHigh;
+ __u16 Reserved;
+ __u16 ByteCount;
+} __packed WRITE_RSP;
+
+/* legacy read request for older servers */
+typedef struct smb_com_readx_req {
+ struct smb_hdr hdr; /* wct = 10 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __le16 MaxCount;
+ __le16 MinCount; /* obsolete */
+ __le32 Reserved;
+ __le16 Remaining;
+ __le16 ByteCount;
+} __packed READX_REQ;
+
+typedef struct smb_com_read_req {
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __le16 MaxCount;
+ __le16 MinCount; /* obsolete */
+ __le32 MaxCountHigh;
+ __le16 Remaining;
+ __le32 OffsetHigh;
+ __le16 ByteCount;
+} __packed READ_REQ;
+
+typedef struct smb_com_read_rsp {
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __le16 Remaining;
+ __le16 DataCompactionMode;
+ __le16 Reserved;
+ __le16 DataLength;
+ __le16 DataOffset;
+ __le16 DataLengthHigh;
+ __u64 Reserved2;
+ __u16 ByteCount;
+ /* read response data immediately follows */
+} __packed READ_RSP;
+
+typedef struct locking_andx_range {
+ __le16 Pid;
+ __le16 Pad;
+ __le32 OffsetHigh;
+ __le32 OffsetLow;
+ __le32 LengthHigh;
+ __le32 LengthLow;
+} __packed LOCKING_ANDX_RANGE;
+
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */
+
+typedef struct smb_com_lock_req {
+ struct smb_hdr hdr; /* wct = 8 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __u8 LockType;
+ __u8 OplockLevel;
+ __le32 Timeout;
+ __le16 NumberOfUnlocks;
+ __le16 NumberOfLocks;
+ __le16 ByteCount;
+ LOCKING_ANDX_RANGE Locks[];
+} __packed LOCK_REQ;
+
+/* lock type */
+#define CIFS_RDLCK 0
+#define CIFS_WRLCK 1
+#define CIFS_UNLCK 2
+typedef struct cifs_posix_lock {
+ __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */
+ __le16 lock_flags; /* 1 = Wait (only valid for setlock) */
+ __le32 pid;
+ __le64 start;
+ __le64 length;
+ /* BB what about additional owner info to identify network client */
+} __packed CIFS_POSIX_LOCK;
+
+typedef struct smb_com_lock_rsp {
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 ByteCount;
+} __packed LOCK_RSP;
+
+typedef struct smb_com_rename_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __le16 SearchAttributes; /* target file attributes */
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName */
+} __packed RENAME_REQ;
+
+ /* copy request flags */
+#define COPY_MUST_BE_FILE 0x0001
+#define COPY_MUST_BE_DIR 0x0002
+#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
+#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
+#define COPY_VERIFY_WRITES 0x0010
+#define COPY_TREE 0x0020
+
+typedef struct smb_com_copy_req {
+ struct smb_hdr hdr; /* wct = 3 */
+ __u16 Tid2;
+ __le16 OpenFunction;
+ __le16 Flags;
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName string */
+} __packed COPY_REQ;
+
+typedef struct smb_com_copy_rsp {
+ struct smb_hdr hdr; /* wct = 1 */
+ __le16 CopyCount; /* number of files copied */
+ __u16 ByteCount; /* may be zero */
+ __u8 BufferFormat; /* 0x04 - only present if errored file follows */
+ unsigned char ErrorFileName[]; /* only present if error in copy */
+} __packed COPY_RSP;
+
+#define CREATE_HARD_LINK 0x103
+#define MOVEFILE_COPY_ALLOWED 0x0002
+#define MOVEFILE_REPLACE_EXISTING 0x0001
+
+typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
+ struct smb_hdr hdr; /* wct = 4 */
+ __le16 SearchAttributes; /* target file attributes */
+ __le16 Flags; /* spec says Information Level */
+ __le32 ClusterCount;
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName */
+} __packed NT_RENAME_REQ;
+
+typedef struct smb_com_rename_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed RENAME_RSP;
+
+typedef struct smb_com_delete_file_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __le16 SearchAttributes;
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char fileName[];
+} __packed DELETE_FILE_REQ;
+
+typedef struct smb_com_delete_file_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed DELETE_FILE_RSP;
+
+typedef struct smb_com_delete_directory_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char DirName[];
+} __packed DELETE_DIRECTORY_REQ;
+
+typedef struct smb_com_delete_directory_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed DELETE_DIRECTORY_RSP;
+
+typedef struct smb_com_create_directory_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char DirName[];
+} __packed CREATE_DIRECTORY_REQ;
+
+typedef struct smb_com_create_directory_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed CREATE_DIRECTORY_RSP;
+
+typedef struct smb_com_query_information_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __le16 ByteCount; /* 1 + namelen + 1 */
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char FileName[];
+} __packed QUERY_INFORMATION_REQ;
+
+typedef struct smb_com_query_information_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ __le16 attr;
+ __le32 last_write_time;
+ __le32 size;
+ __u16 reserved[5];
+ __le16 ByteCount; /* bcc = 0 */
+} __packed QUERY_INFORMATION_RSP;
+
+typedef struct smb_com_setattr_req {
+ struct smb_hdr hdr; /* wct = 8 */
+ __le16 attr;
+ __le32 last_write_time;
+ __le16 reserved[5]; /* must be zero */
+ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char fileName[];
+} __packed SETATTR_REQ;
+
+typedef struct smb_com_setattr_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} __packed SETATTR_RSP;
+
+/* empty wct response to setattr */
+
+/*******************************************************/
+/* NT Transact structure definitions follow */
+/* Currently only ioctl, acl (get security descriptor) */
+/* and notify are implemented */
+/*******************************************************/
+typedef struct smb_com_ntransact_req {
+ struct smb_hdr hdr; /* wct >= 19 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+ /* SetupCount words follow then */
+ __le16 ByteCount;
+ __u8 Pad[3];
+ __u8 Parms[];
+} __packed NTRANSACT_REQ;
+
+typedef struct smb_com_ntransact_rsp {
+ struct smb_hdr hdr; /* wct = 18 */
+ __u8 Reserved[3];
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 ParameterDisplacement;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __le32 DataDisplacement;
+ __u8 SetupCount; /* 0 */
+ __u16 ByteCount;
+ /* __u8 Pad[3]; */
+ /* parms and data follow */
+} __packed NTRANSACT_RSP;
+
+typedef struct smb_com_transaction_ioctl_req {
+ struct smb_hdr hdr; /* wct = 23 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+ __le32 FunctionCode;
+ __u16 Fid;
+ __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
+ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
+ __le16 ByteCount;
+ __u8 Pad[3];
+ __u8 Data[];
+} __packed TRANSACT_IOCTL_REQ;
+
+typedef struct smb_com_transaction_compr_ioctl_req {
+ struct smb_hdr hdr; /* wct = 23 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+ __le32 FunctionCode;
+ __u16 Fid;
+ __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
+ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
+ __le16 ByteCount;
+ __u8 Pad[3];
+ __le16 compression_state; /* See below for valid flags */
+} __packed TRANSACT_COMPR_IOCTL_REQ;
+
+/* compression state flags */
+#define COMPRESSION_FORMAT_NONE 0x0000
+#define COMPRESSION_FORMAT_DEFAULT 0x0001
+#define COMPRESSION_FORMAT_LZNT1 0x0002
+
+typedef struct smb_com_transaction_ioctl_rsp {
+ struct smb_hdr hdr; /* wct = 19 */
+ __u8 Reserved[3];
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 ParameterDisplacement;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __le32 DataDisplacement;
+ __u8 SetupCount; /* 1 */
+ __le16 ReturnedDataLen;
+ __le16 ByteCount;
+} __packed TRANSACT_IOCTL_RSP;
+
+#define CIFS_ACL_OWNER 1
+#define CIFS_ACL_GROUP 2
+#define CIFS_ACL_DACL 4
+#define CIFS_ACL_SACL 8
+
+typedef struct smb_com_transaction_qsec_req {
+ struct smb_hdr hdr; /* wct = 19 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* no setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 6 = QUERY_SECURITY_DESC */
+ __le16 ByteCount; /* bcc = 3 + 8 */
+ __u8 Pad[3];
+ __u16 Fid;
+ __u16 Reserved2;
+ __le32 AclFlags;
+} __packed QUERY_SEC_DESC_REQ;
+
+
+typedef struct smb_com_transaction_ssec_req {
+ struct smb_hdr hdr; /* wct = 19 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* no setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 3 = SET_SECURITY_DESC */
+ __le16 ByteCount; /* bcc = 3 + 8 */
+ __u8 Pad[3];
+ __u16 Fid;
+ __u16 Reserved2;
+ __le32 AclFlags;
+} __packed SET_SEC_DESC_REQ;
+
+typedef struct smb_com_transaction_change_notify_req {
+ struct smb_hdr hdr; /* wct = 23 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand;/* 4 = Change Notify */
+ __le32 CompletionFilter; /* operation to monitor */
+ __u16 Fid;
+ __u8 WatchTree; /* 1 = Monitor subdirectories */
+ __u8 Reserved2;
+ __le16 ByteCount;
+/* __u8 Pad[3];*/
+/* __u8 Data[];*/
+} __packed TRANSACT_CHANGE_NOTIFY_REQ;
+
+/* BB eventually change to use generic ntransact rsp struct
+ and validation routine */
+typedef struct smb_com_transaction_change_notify_rsp {
+ struct smb_hdr hdr; /* wct = 18 */
+ __u8 Reserved[3];
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 ParameterDisplacement;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __le32 DataDisplacement;
+ __u8 SetupCount; /* 0 */
+ __u16 ByteCount;
+ /* __u8 Pad[3]; */
+} __packed TRANSACT_CHANGE_NOTIFY_RSP;
+
+struct cifs_quota_data {
+ __u32 rsrvd1; /* 0 */
+ __u32 sid_size;
+ __u64 rsrvd2; /* 0 */
+ __u64 space_used;
+ __u64 soft_limit;
+ __u64 hard_limit;
+ char sid[]; /* variable size? */
+} __packed;
+
+/* quota sub commands */
+#define QUOTA_LIST_CONTINUE 0
+#define QUOTA_LIST_START 0x100
+#define QUOTA_FOR_SID 0x101
+
+struct trans2_req {
+ /* struct smb_hdr hdr precedes. Set wct = 14+ */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* 1st setup word - SetupCount words follow */
+ __le16 ByteCount;
+} __packed;
+
+struct smb_t2_req {
+ struct smb_hdr hdr;
+ struct trans2_req t2_req;
+} __packed;
+
+struct trans2_resp {
+ /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __u16 Reserved;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 ParameterDisplacement;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __le16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1;
+ /* SetupWords[SetupCount];
+ __u16 ByteCount;
+ __u16 Reserved2;*/
+ /* data area follows */
+} __packed;
+
+struct smb_t2_rsp {
+ struct smb_hdr hdr;
+ struct trans2_resp t2_rsp;
+} __packed;
+
+/* PathInfo/FileInfo infolevels */
+#define SMB_INFO_STANDARD 1
+#define SMB_SET_FILE_EA 2
+#define SMB_QUERY_FILE_EA_SIZE 2
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_IS_NAME_VALID 6
+#define SMB_QUERY_FILE_BASIC_INFO 0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_EA_INFO 0x103
+#define SMB_QUERY_FILE_NAME_INFO 0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALL_INFO 0x107
+#define SMB_QUERY_ALT_NAME_INFO 0x108
+#define SMB_QUERY_FILE_STREAM_INFO 0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+#define SMB_QUERY_FILE_UNIX_BASIC 0x200
+#define SMB_QUERY_FILE_UNIX_LINK 0x201
+#define SMB_QUERY_POSIX_ACL 0x204
+#define SMB_QUERY_XATTR 0x205 /* e.g. system EA name space */
+#define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
+#define SMB_QUERY_POSIX_PERMISSION 0x207
+#define SMB_QUERY_POSIX_LOCK 0x208
+/* #define SMB_POSIX_OPEN 0x209 */
+/* #define SMB_POSIX_UNLINK 0x20a */
+#define SMB_QUERY_FILE__UNIX_INFO2 0x20b
+#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
+#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
+#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
+#define SMB_QUERY_FILE_POSITION_INFO 0x3f6
+#define SMB_QUERY_FILE_MODE_INFO 0x3f8
+#define SMB_QUERY_FILE_ALGN_INFO 0x3f9
+
+
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+#define SMB_SET_FILE_UNIX_BASIC 0x200
+#define SMB_SET_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_HLINK 0x203
+#define SMB_SET_POSIX_ACL 0x204
+#define SMB_SET_XATTR 0x205
+#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
+#define SMB_SET_POSIX_LOCK 0x208
+#define SMB_POSIX_OPEN 0x209
+#define SMB_POSIX_UNLINK 0x20a
+#define SMB_SET_FILE_UNIX_INFO2 0x20b
+#define SMB_SET_FILE_BASIC_INFO2 0x3ec
+#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
+#define SMB_FILE_ALL_INFO2 0x3fa
+#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
+#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
+#define SMB_FILE_MOVE_CLUSTER_INFO 0x407
+#define SMB_FILE_QUOTA_INFO 0x408
+#define SMB_FILE_REPARSEPOINT_INFO 0x409
+#define SMB_FILE_MAXIMUM_INFO 0x40d
+
+/* Find File infolevels */
+#define SMB_FIND_FILE_INFO_STANDARD 0x001
+#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002
+#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
+#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
+#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
+#define SMB_FIND_FILE_UNIX 0x202
+/* #define SMB_FIND_FILE_POSIX_INFO 0x064 */
+
+typedef struct smb_com_transaction2_qpi_req {
+ struct smb_hdr hdr; /* wct = 14+ */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* one setup word */
+ __le16 ByteCount;
+ __u8 Pad;
+ __le16 InformationLevel;
+ __u32 Reserved4;
+ char FileName[];
+} __packed TRANSACTION2_QPI_REQ;
+
+typedef struct smb_com_transaction2_qpi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word is present for infolevels > 100 */
+} __packed TRANSACTION2_QPI_RSP;
+
+typedef struct smb_com_transaction2_spi_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* one setup word */
+ __le16 ByteCount;
+ __u8 Pad;
+ __u16 Pad1;
+ __le16 InformationLevel;
+ __u32 Reserved4;
+ char FileName[];
+} __packed TRANSACTION2_SPI_REQ;
+
+typedef struct smb_com_transaction2_spi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word is present for infolevels > 100 */
+} __packed TRANSACTION2_SPI_RSP;
+
+struct set_file_rename {
+ __le32 overwrite; /* 1 = overwrite dest */
+ __u32 root_fid; /* zero */
+ __le32 target_name_len;
+ char target_name[]; /* Must be unicode */
+} __packed;
+
+struct smb_com_transaction2_sfi_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* one setup word */
+ __le16 ByteCount;
+ __u8 Pad;
+ __u16 Pad1;
+ __u16 Fid;
+ __le16 InformationLevel;
+ __u16 Reserved4;
+ __u8 payload[];
+} __packed;
+
+struct smb_com_transaction2_sfi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+} __packed;
+
+struct smb_t2_qfi_req {
+ struct smb_hdr hdr;
+ struct trans2_req t2;
+ __u8 Pad;
+ __u16 Fid;
+ __le16 InformationLevel;
+} __packed;
+
+struct smb_t2_qfi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+} __packed;
+
+/*
+ * Flags on T2 FINDFIRST and FINDNEXT
+ */
+#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001
+#define CIFS_SEARCH_CLOSE_AT_END 0x0002
+#define CIFS_SEARCH_RETURN_RESUME 0x0004
+#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008
+#define CIFS_SEARCH_BACKUP_SEARCH 0x0010
+
+/*
+ * Size of the resume key on FINDFIRST and FINDNEXT calls
+ */
+#define CIFS_SMB_RESUME_KEY_SIZE 4
+
+typedef struct smb_com_transaction2_ffirst_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __le16 SubCommand; /* TRANS2_FIND_FIRST */
+ __le16 ByteCount;
+ __u8 Pad;
+ __le16 SearchAttributes;
+ __le16 SearchCount;
+ __le16 SearchFlags;
+ __le16 InformationLevel;
+ __le32 SearchStorageType;
+ char FileName[];
+} __packed TRANSACTION2_FFIRST_REQ;
+
+typedef struct smb_com_transaction2_ffirst_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+} __packed TRANSACTION2_FFIRST_RSP;
+
+typedef struct smb_com_transaction2_ffirst_rsp_parms {
+ __u16 SearchHandle;
+ __le16 SearchCount;
+ __le16 EndofSearch;
+ __le16 EAErrorOffset;
+ __le16 LastNameOffset;
+} __packed T2_FFIRST_RSP_PARMS;
+
+typedef struct smb_com_transaction2_fnext_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __le16 SubCommand; /* TRANS2_FIND_NEXT */
+ __le16 ByteCount;
+ __u8 Pad;
+ __u16 SearchHandle;
+ __le16 SearchCount;
+ __le16 InformationLevel;
+ __u32 ResumeKey;
+ __le16 SearchFlags;
+ char ResumeFileName[];
+} __packed TRANSACTION2_FNEXT_REQ;
+
+typedef struct smb_com_transaction2_fnext_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+} __packed TRANSACTION2_FNEXT_RSP;
+
+typedef struct smb_com_transaction2_fnext_rsp_parms {
+ __le16 SearchCount;
+ __le16 EndofSearch;
+ __le16 EAErrorOffset;
+ __le16 LastNameOffset;
+} __packed T2_FNEXT_RSP_PARMS;
+
+/* QFSInfo Levels */
+#define SMB_INFO_ALLOCATION 1
+#define SMB_INFO_VOLUME 2
+#define SMB_QUERY_FS_VOLUME_INFO 0x102
+#define SMB_QUERY_FS_SIZE_INFO 0x103
+#define SMB_QUERY_FS_DEVICE_INFO 0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#define SMB_QUERY_CIFS_UNIX_INFO 0x200
+#define SMB_QUERY_POSIX_FS_INFO 0x201
+#define SMB_QUERY_POSIX_WHO_AM_I 0x202
+#define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203
+#define SMB_QUERY_FS_PROXY 0x204 /* WAFS enabled. Returns structure
+ FILE_SYSTEM__UNIX_INFO to tell
+ whether new NTIOCTL available
+ (0xACE) for WAN friendly SMB
+ operations to be carried */
+#define SMB_QUERY_LABEL_INFO 0x3ea
+#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
+#define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef
+#define SMB_QUERY_OBJECTID_INFO 0x3f0
+
+typedef struct smb_com_transaction2_qfsi_req {
+ struct smb_hdr hdr; /* wct = 14+ */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* one setup word */
+ __le16 ByteCount;
+ __u8 Pad;
+ __le16 InformationLevel;
+} __packed TRANSACTION2_QFSI_REQ;
+
+typedef struct smb_com_transaction_qfsi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u8 Pad; /* may be three bytes? *//* followed by data area */
+} __packed TRANSACTION2_QFSI_RSP;
+
+typedef struct whoami_rsp_data { /* Query level 0x202 */
+ __u32 flags; /* 0 = Authenticated user 1 = GUEST */
+ __u32 mask; /* which flags bits server understands ie 0x0001 */
+ __u64 unix_user_id;
+ __u64 unix_user_gid;
+ __u32 number_of_supplementary_gids; /* may be zero */
+ __u32 number_of_sids; /* may be zero */
+ __u32 length_of_sid_array; /* in bytes - may be zero */
+ __u32 pad; /* reserved - MBZ */
+ /* __u64 gid_array[0]; */ /* may be empty */
+ /* __u8 * psid_list */ /* may be empty */
+} __packed WHOAMI_RSP_DATA;
+
+/* SETFSInfo Levels */
+#define SMB_SET_CIFS_UNIX_INFO 0x200
+/* level 0x203 is defined above in list of QFS info levels */
+/* #define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 */
+
+/* Level 0x200 request structure follows */
+typedef struct smb_com_transaction2_setfsi_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount; /* 4 */
+ __le16 ParameterOffset;
+ __le16 DataCount; /* 12 */
+ __le16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
+ __le16 ByteCount;
+ __u8 Pad;
+ __u16 FileNum; /* Parameters start. */
+ __le16 InformationLevel;/* Parameters end. */
+ __le16 ClientUnixMajor; /* Data start. */
+ __le16 ClientUnixMinor;
+ __le64 ClientUnixCap; /* Data end */
+} __packed TRANSACTION2_SETFSI_REQ;
+
+/* level 0x203 request structure follows */
+typedef struct smb_com_transaction2_setfs_enc_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount; /* 4 */
+ __le16 ParameterOffset;
+ __le16 DataCount; /* 12 */
+ __le16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
+ __le16 ByteCount;
+ __u8 Pad;
+ __u16 Reserved4; /* Parameters start. */
+ __le16 InformationLevel;/* Parameters end. */
+ /* NTLMSSP Blob, Data start. */
+} __packed TRANSACTION2_SETFSI_ENC_REQ;
+
+/* response for setfsinfo levels 0x200 and 0x203 */
+typedef struct smb_com_transaction2_setfsi_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+} __packed TRANSACTION2_SETFSI_RSP;
+
+typedef struct smb_com_transaction2_get_dfs_refer_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __le16 TotalParameterCount;
+ __le16 TotalDataCount;
+ __le16 MaxParameterCount;
+ __le16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __le16 Flags;
+ __le32 Timeout;
+ __u16 Reserved2;
+ __le16 ParameterCount;
+ __le16 ParameterOffset;
+ __le16 DataCount;
+ __le16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __le16 SubCommand; /* one setup word */
+ __le16 ByteCount;
+ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max response length
+ perhaps?) followed by one byte pad - doesn't
+ seem to matter though */
+ __le16 MaxReferralLevel;
+ char RequestFileName[];
+} __packed TRANSACTION2_GET_DFS_REFER_REQ;
+
+#define DFS_VERSION cpu_to_le16(0x0003)
+
+/* DFS server target type */
+#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
+#define DFS_TYPE_ROOT 0x0001
+
+/* Referral Entry Flags */
+#define DFS_NAME_LIST_REF 0x0200 /* set for domain or DC referral responses */
+#define DFS_TARGET_SET_BOUNDARY 0x0400 /* only valid with version 4 dfs req */
+
+typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
+ __le16 VersionNumber; /* must be 3 or 4 */
+ __le16 Size;
+ __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
+ __le16 ReferralEntryFlags;
+ __le32 TimeToLive;
+ __le16 DfsPathOffset;
+ __le16 DfsAlternatePathOffset;
+ __le16 NetworkAddressOffset; /* offset of the link target */
+ __u8 ServiceSiteGuid[16]; /* MBZ, ignored */
+} __packed REFERRAL3;
+
+struct get_dfs_referral_rsp {
+ __le16 PathConsumed;
+ __le16 NumberOfReferrals;
+ __le32 DFSFlags;
+ REFERRAL3 referrals[]; /* array of level 3 dfs_referral structures */
+ /* followed by the strings pointed to by the referral structures */
+} __packed;
+
+typedef struct smb_com_transaction_get_dfs_refer_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u8 Pad;
+ struct get_dfs_referral_rsp dfs_data;
+} __packed TRANSACTION2_GET_DFS_REFER_RSP;
+
+/* DFS Flags */
+#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
+#define DFSREF_STORAGE_SERVER 0x00000002 /* no further ref requests needed */
+#define DFSREF_TARGET_FAILBACK 0x00000004 /* only for DFS referral version 4 */
+
+/*
+ ************************************************************************
+ * All structs for everything above the SMB PDUs themselves
+ * (such as the T2 level specific data) go here
+ ************************************************************************
+ */
+
+/*
+ * Information on a server
+ */
+
+struct serverInfo {
+ char name[16];
+ unsigned char versionMajor;
+ unsigned char versionMinor;
+ unsigned long type;
+ unsigned int commentOffset;
+} __packed;
+
+/*
+ * The following structure is the format of the data returned on a NetShareEnum
+ * with level "90" (x5A)
+ */
+
+struct shareInfo {
+ char shareName[13];
+ char pad;
+ unsigned short type;
+ unsigned int commentOffset;
+} __packed;
+
+struct aliasInfo {
+ char aliasName[9];
+ char pad;
+ unsigned int commentOffset;
+ unsigned char type[2];
+} __packed;
+
+struct aliasInfo92 {
+ int aliasNameOffset;
+ int serverNameOffset;
+ int shareNameOffset;
+} __packed;
+
+typedef struct {
+ __le32 fsid;
+ __le32 SectorsPerAllocationUnit;
+ __le32 TotalAllocationUnits;
+ __le32 FreeAllocationUnits;
+ __le16 BytesPerSector;
+} __packed FILE_SYSTEM_ALLOC_INFO;
+
+typedef struct {
+ __le16 MajorVersionNumber;
+ __le16 MinorVersionNumber;
+ __le64 Capability;
+} __packed FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
+
+/* Version numbers for CIFS UNIX major and minor. */
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
+/* Linux/Unix extensions capability flags */
+#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
+#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */
+#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
+#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */
+#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
+ calls including posix open
+ and posix unlink */
+#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up to 0xFFFF00 */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */
+#define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and QFS PROXY call */
+#ifdef CONFIG_CIFS_POSIX
+/* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send
+ LockingX instead of posix locking call on unix sess (and we do not expect
+ LockingX to use different (ie Windows) semantics than posix locking on
+ the same session (if WINE needs to do this later, we can add this cap
+ back in later */
+/* #define CIFS_UNIX_CAP_MASK 0x000000fb */
+#define CIFS_UNIX_CAP_MASK 0x000003db
+#else
+#define CIFS_UNIX_CAP_MASK 0x00000013
+#endif /* CONFIG_CIFS_POSIX */
+
+
+#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
+
+/******************************************************************************/
+/* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
+/******************************************************************************/
+typedef struct { /* data block encoding of response to level 263 QPathInfo */
+ struct_group_attr(common_attributes, __packed,
+ __le64 CreationTime;
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le32 Attributes;
+ );
+ __u32 Pad1;
+ __le64 AllocationSize;
+ __le64 EndOfFile; /* size ie offset to first free byte in file */
+ __le32 NumberOfLinks; /* hard links */
+ __u8 DeletePending;
+ __u8 Directory;
+ __u16 Pad2;
+ __le32 EASize;
+ __le32 FileNameLength;
+ union {
+ char __pad;
+ DECLARE_FLEX_ARRAY(char, FileName);
+ };
+} __packed FILE_ALL_INFO; /* level 0x107 QPathInfo */
+
+typedef struct {
+ __le64 AllocationSize;
+ __le64 EndOfFile; /* size ie offset to first free byte in file */
+ __le32 NumberOfLinks; /* hard links */
+ __u8 DeletePending;
+ __u8 Directory;
+ __u16 Pad;
+} __packed FILE_STANDARD_INFO; /* level 0x102 QPathInfo */
+
+
+/* defines for enumerating possible values of the Unix type field below */
+#define UNIX_FILE 0
+#define UNIX_DIR 1
+#define UNIX_SYMLINK 2
+#define UNIX_CHARDEV 3
+#define UNIX_BLOCKDEV 4
+#define UNIX_FIFO 5
+#define UNIX_SOCKET 6
+typedef struct {
+ __le64 EndOfFile;
+ __le64 NumOfBytes;
+ __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
+ __le64 LastAccessTime;
+ __le64 LastModificationTime;
+ __le64 Uid;
+ __le64 Gid;
+ __le32 Type;
+ __le64 DevMajor;
+ __le64 DevMinor;
+ __le64 UniqueId;
+ __le64 Permissions;
+ __le64 Nlinks;
+} __packed FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */
+
+typedef struct {
+ DECLARE_FLEX_ARRAY(char, LinkDest);
+} __packed FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */
+
+/* The following three structures are needed only for
+ setting time to NT4 and some older servers via
+ the primitive DOS time format */
+typedef struct {
+ __u16 Day:5;
+ __u16 Month:4;
+ __u16 Year:7;
+} __packed SMB_DATE;
+
+typedef struct {
+ __u16 TwoSeconds:5;
+ __u16 Minutes:6;
+ __u16 Hours:5;
+} __packed SMB_TIME;
+
+typedef struct {
+ __le16 CreationDate; /* SMB Date see above */
+ __le16 CreationTime; /* SMB Time */
+ __le16 LastAccessDate;
+ __le16 LastAccessTime;
+ __le16 LastWriteDate;
+ __le16 LastWriteTime;
+ __le32 DataSize; /* File Size (EOF) */
+ __le32 AllocationSize;
+ __le16 Attributes; /* verify not u32 */
+ __le32 EASize;
+} __packed FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */
+
+struct file_allocation_info {
+ __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
+} __packed; /* size used on disk, for level 0x103 for set, 0x105 for query */
+
+struct file_end_of_file_info {
+ __le64 FileSize; /* offset to end of file */
+} __packed; /* size info, level 0x104 for set, 0x106 for query */
+
+struct file_alt_name_info {
+ DECLARE_FLEX_ARRAY(__u8, alt_name);
+} __packed; /* level 0x0108 */
+
+struct file_stream_info {
+ __le32 number_of_streams; /* BB check sizes and verify location */
+ /* followed by info on streams themselves
+ u64 size;
+ u64 allocation_size
+ stream info */
+}; /* level 0x109 */
+
+struct file_compression_info {
+ __le64 compressed_size;
+ __le16 format;
+ __u8 unit_shift;
+ __u8 ch_shift;
+ __u8 cl_shift;
+ __u8 pad[3];
+} __packed; /* level 0x10b */
+
+/* POSIX ACL set/query path info structures */
+#define CIFS_ACL_VERSION 1
+struct cifs_posix_ace { /* access control entry (ACE) */
+ __u8 cifs_e_tag;
+ __u8 cifs_e_perm;
+ __le64 cifs_uid; /* or gid */
+} __packed;
+
+struct cifs_posix_acl { /* access control list (ACL) */
+ __le16 version;
+ __le16 access_entry_count; /* access ACL - count of entries */
+ __le16 default_entry_count; /* default ACL - count of entries */
+ struct cifs_posix_ace ace_array[];
+ /* followed by struct cifs_posix_ace default_ace_array[] */
+} __packed; /* level 0x204 */
+
+/* types of access control entries already defined in posix_acl.h */
+/* #define CIFS_POSIX_ACL_USER_OBJ 0x01
+#define CIFS_POSIX_ACL_USER 0x02
+#define CIFS_POSIX_ACL_GROUP_OBJ 0x04
+#define CIFS_POSIX_ACL_GROUP 0x08
+#define CIFS_POSIX_ACL_MASK 0x10
+#define CIFS_POSIX_ACL_OTHER 0x20 */
+
+/* types of perms */
+/* #define CIFS_POSIX_ACL_EXECUTE 0x01
+#define CIFS_POSIX_ACL_WRITE 0x02
+#define CIFS_POSIX_ACL_READ 0x04 */
+
+/* end of POSIX ACL definitions */
+
+/* POSIX Open Flags */
+#define SMB_O_RDONLY 0x1
+#define SMB_O_WRONLY 0x2
+#define SMB_O_RDWR 0x4
+#define SMB_O_CREAT 0x10
+#define SMB_O_EXCL 0x20
+#define SMB_O_TRUNC 0x40
+#define SMB_O_APPEND 0x80
+#define SMB_O_SYNC 0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT 0x800
+
+typedef struct {
+ __le32 OpenFlags; /* same as NT CreateX */
+ __le32 PosixOpenFlags;
+ __le64 Permissions;
+ __le16 Level; /* reply level requested (see QPathInfo levels) */
+} __packed OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
+
+typedef struct {
+ __le16 OplockFlags;
+ __u16 Fid;
+ __le32 CreateAction;
+ __le16 ReturnedLevel;
+ __le16 Pad;
+ /* struct following varies based on requested level */
+} __packed OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
+
+#define SMB_POSIX_UNLINK_FILE_TARGET 0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
+
+struct unlink_psx_rq { /* level 0x20a SetPathInfo */
+ __le16 type;
+} __packed;
+
+struct file_internal_info {
+ __le64 UniqueId; /* inode number */
+} __packed; /* level 0x3ee */
+
+struct file_mode_info {
+ __le32 Mode;
+} __packed; /* level 0x3f8 */
+
+struct file_attrib_tag {
+ __le32 Attribute;
+ __le32 ReparseTag;
+} __packed; /* level 0x40b */
+
+
+/********************************************************/
+/* FindFirst/FindNext transact2 data buffer formats */
+/********************************************************/
+
+typedef struct {
+ __le32 NextEntryOffset;
+ __u32 ResumeKey; /* as with FileIndex - no need to convert */
+ FILE_UNIX_BASIC_INFO basic;
+ union {
+ char __pad;
+ DECLARE_FLEX_ARRAY(char, FileName);
+ };
+} __packed FILE_UNIX_INFO; /* level 0x202 */
+
+typedef struct {
+ __u32 ResumeKey;
+ __le16 CreationDate; /* SMB Date */
+ __le16 CreationTime; /* SMB Time */
+ __le16 LastAccessDate;
+ __le16 LastAccessTime;
+ __le16 LastWriteDate;
+ __le16 LastWriteTime;
+ __le32 DataSize; /* File Size (EOF) */
+ __le32 AllocationSize;
+ __le16 Attributes; /* verify not u32 */
+ __u8 FileNameLength;
+ char FileName[];
+} __packed FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
+
+
+struct fea {
+ unsigned char EA_flags;
+ __u8 name_len;
+ __le16 value_len;
+ char name[];
+ /* optionally followed by value */
+} __packed;
+/* flags for _FEA.fEA */
+#define FEA_NEEDEA 0x80 /* need EA bit */
+
+struct fealist {
+ __le32 list_len;
+ struct fea list;
+} __packed;
+
+/* used to hold an arbitrary blob of data */
+struct data_blob {
+ __u8 *data;
+ size_t length;
+ void (*free) (struct data_blob *data_blob);
+} __packed;
+
+
+#ifdef CONFIG_CIFS_POSIX
+/*
+ For better POSIX semantics from Linux client, (even better
+ than the existing CIFS Unix Extensions) we need updated PDUs for:
+
+ 1) PosixCreateX - to set and return the mode, inode#, device info and
+ perhaps add a CreateDevice - to create Pipes and other special .inodes
+ Also note POSIX open flags
+ 2) Close - to return the last write time to do cache across close
+ more safely
+ 3) FindFirst return unique inode number - what about resume key, two
+ forms short (matches readdir) and full (enough info to cache inodes)
+ 4) Mkdir - set mode
+
+ And under consideration:
+ 5) FindClose2 (return nanosecond timestamp ??)
+ 6) Use nanosecond timestamps throughout all time fields if
+ corresponding attribute flag is set
+ 7) sendfile - handle based copy
+
+ what about fixing 64 bit alignment
+
+ There are also various legacy SMB/CIFS requests used as is
+
+ From existing Lanman and NTLM dialects:
+ --------------------------------------
+ NEGOTIATE
+ SESSION_SETUP_ANDX (BB which?)
+ TREE_CONNECT_ANDX (BB which wct?)
+ TREE_DISCONNECT (BB add volume timestamp on response)
+ LOGOFF_ANDX
+ DELETE (note delete open file behavior)
+ DELETE_DIRECTORY
+ READ_AND_X
+ WRITE_AND_X
+ LOCKING_AND_X (note posix lock semantics)
+ RENAME (note rename across dirs and open file rename posix behaviors)
+ NT_RENAME (for hardlinks) Is this good enough for all features?
+ FIND_CLOSE2
+ TRANSACTION2 (18 cases)
+ SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
+ (BB verify that never need to set allocation size)
+ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via
+ Unix ext?)
+
+ COPY (note support for copy across directories) - FUTURE, OPTIONAL
+ setting/getting OS/2 EAs - FUTURE (BB can this handle
+ setting Linux xattrs perfectly) - OPTIONAL
+ dnotify - FUTURE, OPTIONAL
+ quota - FUTURE, OPTIONAL
+
+ Note that various requests implemented for NT interop such as
+ NT_TRANSACT (IOCTL) QueryReparseInfo
+ are unneeded to servers compliant with the CIFS POSIX extensions
+
+ From CIFS Unix Extensions:
+ -------------------------
+ T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
+ T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
+ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
+ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) BB check for missing
+ inode fields
+ Actually a need QUERY_FILE_UNIX_INFO
+ since has inode num
+ BB what about a) blksize/blkbits/blocks
+ b) i_version
+ c) i_rdev
+ d) notify mask?
+ e) generation
+ f) size_seqcount
+ T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
+ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
+ T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
+ */
+
+/* xsymlink is a symlink format (used by MacOS) that can be used
+ to save symlink info in a regular file when
+ mounted to operating systems that do not
+ support the cifs Unix extensions or EAs (for xattr
+ based symlinks). For such a file to be recognized
+ as containing symlink data:
+
+ 1) file size must be 1067,
+ 2) signature must begin file data,
+ 3) length field must be set to ASCII representation
+ of a number which is less than or equal to 1024,
+ 4) md5 must match that of the path data */
+
+struct xsymlink {
+ /* 1067 bytes */
+ char signature[4]; /* XSym */ /* not null terminated */
+ char cr0; /* \n */
+/* ASCII representation of length (4 bytes decimal) terminated by \n not null */
+ char length[4];
+ char cr1; /* \n */
+/* md5 of valid subset of path ie path[0] through path[length-1] */
+ __u8 md5[32];
+ char cr2; /* \n */
+/* if room left, then end with \n then 0x20s by convention but not required */
+ char path[1024];
+} __packed;
+
+typedef struct file_xattr_info {
+ /* BB do we need another field for flags? BB */
+ __u32 xattr_name_len;
+ __u32 xattr_value_len;
+ char xattr_name[];
+ /* followed by xattr_value[xattr_value_len], no pad */
+} __packed FILE_XATTR_INFO; /* extended attribute info level 0x205 */
+
+/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
+
+typedef struct file_chattr_info {
+ __le64 mask; /* list of all possible attribute bits */
+ __le64 mode; /* list of actual attribute bits on this inode */
+} __packed FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */
+#endif /* POSIX */
+
+#endif /* _SMB1PDU_H */
diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h
new file mode 100644
index 000000000000..5f522d359952
--- /dev/null
+++ b/fs/smb/client/smb1proto.h
@@ -0,0 +1,350 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2002,2008
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ */
+#ifndef _SMB1PROTO_H
+#define _SMB1PROTO_H
+
+#include <linux/uidgid_types.h>
+#include <linux/unaligned.h>
+#include "../common/smb2pdu.h"
+#include "cifsglob.h"
+
+struct cifs_unix_set_info_args {
+ __u64 ctime;
+ __u64 atime;
+ __u64 mtime;
+ __u64 mode;
+ kuid_t uid;
+ kgid_t gid;
+ dev_t device;
+};
+
+#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
+
+/*
+ * cifssmb.c
+ */
+int small_smb_init_no_tc(const int smb_command, const int wct,
+ struct cifs_ses *ses, void **request_buf);
+int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
+ struct cifs_tcon *tcon, const struct nls_table *nls_codepage);
+int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon);
+int CIFSSMBEcho(struct TCP_Server_Info *server);
+int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
+int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, __u16 type,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb,
+ struct dentry *dentry);
+int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
+int CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
+ struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb);
+int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
+ __u32 posix_flags, __u64 mode, __u16 *netfid,
+ FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
+ const char *name, const struct nls_table *nls_codepage,
+ int remap);
+int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, const int openDisposition,
+ const int access_flags, const int create_options,
+ __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info,
+ const struct nls_table *nls_codepage, int remap);
+int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
+ int *oplock, FILE_ALL_INFO *buf);
+int cifs_async_readv(struct cifs_io_subrequest *rdata);
+int CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *pbuf_type);
+int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, const char *buf);
+void cifs_async_writev(struct cifs_io_subrequest *wdata);
+int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec);
+int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u16 netfid, const __u8 lock_type,
+ const __u32 num_unlock, const __u32 num_lock,
+ LOCKING_ANDX_RANGE *buf);
+int CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u16 smb_file_id, const __u32 netpid, const __u64 len,
+ const __u64 offset, const __u32 numUnlock, const __u32 numLock,
+ const __u8 lockType, const bool waitFlag,
+ const __u8 oplock_level);
+int CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u16 smb_file_id, const __u32 netpid,
+ const loff_t start_offset, const __u64 len,
+ struct file_lock *pLockData, const __u16 lock_type,
+ const bool waitFlag);
+int CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon,
+ int smb_file_id);
+int CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon,
+ int smb_file_id);
+int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
+ struct dentry *source_dentry, const char *from_name,
+ const char *to_name, struct cifs_sb_info *cifs_sb);
+int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
+ int netfid, const char *target_name,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+ struct dentry *source_dentry, const char *from_name,
+ const char *to_name, struct cifs_sb_info *cifs_sb);
+int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName,
+ char **symlinkinfo,
+ const struct nls_table *nls_codepage, int remap);
+int cifs_query_reparse_point(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path, u32 *tag, struct kvec *rsp,
+ int *rsp_buftype);
+struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid,
+ struct cifs_tcon *tcon,
+ const char *full_path, bool directory,
+ struct kvec *reparse_iov,
+ struct kvec *xattr_iov);
+int CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
+ __u16 fid);
+int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName, struct posix_acl **acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap);
+int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *fileName, const struct posix_acl *acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap);
+int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
+ const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
+int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
+ __u16 fid, struct smb_ntsd **acl_inf, __u32 *pbuflen,
+ __u32 info);
+int CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
+ __u16 fid, struct smb_ntsd *pntsd, __u32 acllen,
+ int aclflag);
+int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *search_name, FILE_ALL_INFO *data,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ u16 netfid, FILE_ALL_INFO *pFindData);
+int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *search_name, FILE_ALL_INFO *data,
+ int legacy /* old style infolevel */,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
+int CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName,
+ FILE_UNIX_BASIC_INFO *pFindData,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *searchName, struct cifs_sb_info *cifs_sb,
+ __u16 *pnetfid, __u16 search_flags,
+ struct cifs_search_info *psrch_inf, bool msearch);
+int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
+ __u16 searchHandle, __u16 search_flags,
+ struct cifs_search_info *psrch_inf);
+int CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u16 searchHandle);
+int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *search_name, __u64 *inode_number,
+ const struct nls_table *nls_codepage, int remap);
+int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
+ const char *search_name,
+ struct dfs_info3_param **target_nodes,
+ unsigned int *num_of_nodes,
+ const struct nls_table *nls_codepage, int remap);
+int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *FSData);
+int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *FSData);
+int CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon);
+int CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon);
+int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
+int CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ __u64 cap);
+int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *FSData);
+int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *file_name, __u64 size,
+ struct cifs_sb_info *cifs_sb, bool set_allocation,
+ struct dentry *dentry);
+int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile, __u64 size,
+ bool set_allocation);
+int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, __le32 attributes,
+ __le64 write_time, const struct nls_table *nls_codepage,
+ struct cifs_sb_info *cifs_sb);
+int CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const FILE_BASIC_INFO *data, __u16 fid,
+ __u32 pid_of_opener);
+int CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
+ bool delete_file, __u16 fid,
+ __u32 pid_of_opener);
+int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, const FILE_BASIC_INFO *data,
+ const struct nls_table *nls_codepage,
+ struct cifs_sb_info *cifs_sb);
+int CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const struct cifs_unix_set_info_args *args, u16 fid,
+ u32 pid_of_opener);
+int CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *file_name,
+ const struct cifs_unix_set_info_args *args,
+ const struct nls_table *nls_codepage, int remap);
+ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName,
+ const unsigned char *ea_name, char *EAData,
+ size_t buf_size, struct cifs_sb_info *cifs_sb);
+int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, const char *ea_name,
+ const void *ea_value, const __u16 ea_value_len,
+ const struct nls_table *nls_codepage,
+ struct cifs_sb_info *cifs_sb);
+
+/*
+ * smb1debug.c
+ */
+void cifs_dump_detail(void *buf, size_t buf_len,
+ struct TCP_Server_Info *server);
+
+/*
+ * smb1encrypt.c
+ */
+int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+ __u32 *pexpected_response_sequence_number);
+int cifs_verify_signature(struct smb_rqst *rqst,
+ struct TCP_Server_Info *server,
+ __u32 expected_sequence_number);
+
+/*
+ * smb1maperror.c
+ */
+int map_smb_to_linux_error(char *buf, bool logErr);
+int smb1_init_maperror(void);
+int map_and_check_smb_error(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid, bool logErr);
+#if IS_ENABLED(CONFIG_SMB1_KUNIT_TESTS)
+extern const struct ntstatus_to_dos_err *ntstatus_to_dos_map_test;
+extern unsigned int ntstatus_to_dos_num;
+const struct ntstatus_to_dos_err *
+search_ntstatus_to_dos_map_test(__u32 ntstatus);
+extern const struct smb_to_posix_error *mapping_table_ERRDOS_test;
+extern unsigned int mapping_table_ERRDOS_num;
+const struct smb_to_posix_error *
+search_mapping_table_ERRDOS_test(__u16 smb_err);
+extern const struct smb_to_posix_error *mapping_table_ERRSRV_test;
+extern unsigned int mapping_table_ERRSRV_num;
+const struct smb_to_posix_error *
+search_mapping_table_ERRSRV_test(__u16 smb_err);
+#endif
+
+/*
+ * smb1misc.c
+ */
+unsigned int header_assemble(struct smb_hdr *buffer, char smb_command,
+ const struct cifs_tcon *treeCon, int word_count);
+bool is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv);
+unsigned int smbCalcSize(void *buf);
+
+/*
+ * smb1ops.c
+ */
+extern struct smb_version_operations smb1_operations;
+extern struct smb_version_values smb1_values;
+
+void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ struct smb3_fs_context *ctx);
+
+/*
+ * smb1session.c
+ */
+int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ const struct nls_table *nls_cp);
+
+/*
+ * smb1transport.c
+ */
+struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *server,
+ struct smb_rqst *rqst);
+int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
+ char *in_buf, unsigned int in_len, int flags);
+int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+ bool log_error);
+struct mid_q_entry *cifs_setup_request(struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ struct smb_rqst *rqst);
+int SendReceive2(const unsigned int xid, struct cifs_ses *ses,
+ struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
+ const int flags, struct kvec *resp_iov);
+int SendReceive(const unsigned int xid, struct cifs_ses *ses,
+ struct smb_hdr *in_buf, unsigned int in_len,
+ struct smb_hdr *out_buf, int *pbytes_returned,
+ const int flags);
+bool cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+ char *buf, int malformed);
+int checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read,
+ struct TCP_Server_Info *server);
+
+
+static inline __u16
+get_mid(const struct smb_hdr *smb)
+{
+ return le16_to_cpu(smb->Mid);
+}
+
+static inline bool
+compare_mid(__u16 mid, const struct smb_hdr *smb)
+{
+ return mid == le16_to_cpu(smb->Mid);
+}
+
+#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */
+#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */
+
+/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
+static inline void *
+BCC(struct smb_hdr *smb)
+{
+ return (void *)smb + sizeof(*smb) + 2 * smb->WordCount;
+}
+
+/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
+#define pByteArea(smb_var) (BCC(smb_var) + 2)
+
+/* get the unconverted ByteCount for a SMB packet and return it */
+static inline __u16
+get_bcc(struct smb_hdr *hdr)
+{
+ __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+ return get_unaligned_le16(bc_ptr);
+}
+
+/* set the ByteCount for a SMB packet in little-endian */
+static inline void
+put_bcc(__u16 count, struct smb_hdr *hdr)
+{
+ __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+ put_unaligned_le16(count, bc_ptr);
+}
+
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+
+#endif /* _SMB1PROTO_H */
diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c
new file mode 100644
index 000000000000..83bfbf0c068e
--- /dev/null
+++ b/fs/smb/client/smb1session.c
@@ -0,0 +1,995 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ * SMB/CIFS session setup handling routines
+ *
+ * Copyright (c) International Business Machines Corp., 2006, 2009
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ */
+
+#include "cifsproto.h"
+#include "smb1proto.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include "cifs_spnego.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+
+struct sess_data {
+ unsigned int xid;
+ struct cifs_ses *ses;
+ struct TCP_Server_Info *server;
+ struct nls_table *nls_cp;
+ void (*func)(struct sess_data *);
+ int result;
+ unsigned int in_len;
+
+ /* we will send the SMB in three pieces:
+ * a fixed length beginning part, an optional
+ * SPNEGO blob (which can be zero length), and a
+ * last part which will include the strings
+ * and rest of bcc area. This allows us to avoid
+ * a large buffer 17K allocation
+ */
+ int buf0_type;
+ struct kvec iov[3];
+};
+
+static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ SESSION_SETUP_ANDX *pSMB)
+{
+ __u32 capabilities = 0;
+
+ /* init fields common to all four types of SessSetup */
+ /* Note that offsets for first seven fields in req struct are same */
+ /* in CIFS Specs so does not matter which of 3 forms of struct */
+ /* that we use in next few lines */
+ /* Note that header is initialized to zero in header_assemble */
+ pSMB->req.AndXCommand = 0xFF;
+ pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32,
+ CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
+ USHRT_MAX));
+ pSMB->req.MaxMpxCount = cpu_to_le16(server->maxReq);
+ pSMB->req.VcNumber = cpu_to_le16(1);
+ pSMB->req.SessionKey = server->session_key_id;
+
+ /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+ /* BB verify whether signing required on neg or just auth frame (and NTLM case) */
+
+ capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+ if (server->sign)
+ pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ if (ses->capabilities & CAP_UNICODE) {
+ pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+ capabilities |= CAP_UNICODE;
+ }
+ if (ses->capabilities & CAP_STATUS32) {
+ pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+ capabilities |= CAP_STATUS32;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+ capabilities |= CAP_DFS;
+ }
+ if (ses->capabilities & CAP_UNIX)
+ capabilities |= CAP_UNIX;
+
+ return capabilities;
+}
+
+static void
+unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+ int bytes_ret = 0;
+
+ /* Copy OS version */
+ bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Linux version ", 32,
+ nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+ bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, init_utsname()->release,
+ 32, nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+ bcc_ptr += 2; /* trailing null */
+
+ bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ 32, nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+ bcc_ptr += 2; /* trailing null */
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void
+ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+ strcpy(bcc_ptr, init_utsname()->release);
+ bcc_ptr += strlen(init_utsname()->release) + 1;
+
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+ int bytes_ret = 0;
+
+ /* copy domain */
+ if (ses->domainName == NULL) {
+ /*
+ * Sending null domain better than using a bogus domain name (as
+ * we did briefly in 2.6.18) since server will use its default
+ */
+ *bcc_ptr = 0;
+ *(bcc_ptr+1) = 0;
+ bytes_ret = 0;
+ } else
+ bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
+ CIFS_MAX_DOMAINNAME_LEN, nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+ bcc_ptr += 2; /* account for null terminator */
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+ int len;
+
+ /* copy domain */
+ if (ses->domainName != NULL) {
+ len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+ if (WARN_ON_ONCE(len < 0))
+ len = CIFS_MAX_DOMAINNAME_LEN - 1;
+ bcc_ptr += len;
+ } /* else we send a null domain name so server will default to its own domain */
+ *bcc_ptr = 0;
+ bcc_ptr++;
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+ int bytes_ret = 0;
+
+ /* BB FIXME add check that strings less than 335 or will need to send as arrays */
+
+ /* copy user */
+ if (ses->user_name == NULL) {
+ /* null user mount */
+ *bcc_ptr = 0;
+ *(bcc_ptr+1) = 0;
+ } else {
+ bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name,
+ CIFS_MAX_USERNAME_LEN, nls_cp);
+ }
+ bcc_ptr += 2 * bytes_ret;
+ bcc_ptr += 2; /* account for null termination */
+
+ unicode_domain_string(&bcc_ptr, ses, nls_cp);
+ unicode_oslm_strings(&bcc_ptr, nls_cp);
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ char *bcc_ptr = *pbcc_area;
+ int len;
+
+ /* copy user */
+ /* BB what about null user mounts - check that we do this BB */
+ /* copy user */
+ if (ses->user_name != NULL) {
+ len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
+ if (WARN_ON_ONCE(len < 0))
+ len = CIFS_MAX_USERNAME_LEN - 1;
+ bcc_ptr += len;
+ }
+ /* else null user mount */
+ *bcc_ptr = 0;
+ bcc_ptr++; /* account for null termination */
+
+ /* BB check for overflow here */
+
+ ascii_domain_string(&bcc_ptr, ses, nls_cp);
+ ascii_oslm_strings(&bcc_ptr, nls_cp);
+
+ *pbcc_area = bcc_ptr;
+}
+
+static void
+decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ int len;
+ char *data = *pbcc_area;
+
+ cifs_dbg(FYI, "bleft %d\n", bleft);
+
+ kfree(ses->serverOS);
+ ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
+ cifs_dbg(FYI, "serverOS=%s\n", ses->serverOS);
+ len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
+ data += len;
+ bleft -= len;
+ if (bleft <= 0)
+ return;
+
+ kfree(ses->serverNOS);
+ ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
+ cifs_dbg(FYI, "serverNOS=%s\n", ses->serverNOS);
+ len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
+ data += len;
+ bleft -= len;
+ if (bleft <= 0)
+ return;
+
+ kfree(ses->serverDomain);
+ ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
+ cifs_dbg(FYI, "serverDomain=%s\n", ses->serverDomain);
+
+ return;
+}
+
+static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
+ struct cifs_ses *ses,
+ const struct nls_table *nls_cp)
+{
+ int len;
+ char *bcc_ptr = *pbcc_area;
+
+ cifs_dbg(FYI, "decode sessetup ascii. bleft %d\n", bleft);
+
+ len = strnlen(bcc_ptr, bleft);
+ if (len >= bleft)
+ return;
+
+ kfree(ses->serverOS);
+
+ ses->serverOS = kmalloc(len + 1, GFP_KERNEL);
+ if (ses->serverOS) {
+ memcpy(ses->serverOS, bcc_ptr, len);
+ ses->serverOS[len] = 0;
+ if (strncmp(ses->serverOS, "OS/2", 4) == 0)
+ cifs_dbg(FYI, "OS/2 server\n");
+ }
+
+ bcc_ptr += len + 1;
+ bleft -= len + 1;
+
+ len = strnlen(bcc_ptr, bleft);
+ if (len >= bleft)
+ return;
+
+ kfree(ses->serverNOS);
+
+ ses->serverNOS = kmalloc(len + 1, GFP_KERNEL);
+ if (ses->serverNOS) {
+ memcpy(ses->serverNOS, bcc_ptr, len);
+ ses->serverNOS[len] = 0;
+ }
+
+ bcc_ptr += len + 1;
+ bleft -= len + 1;
+
+ len = strnlen(bcc_ptr, bleft);
+ if (len > bleft)
+ return;
+
+ /*
+ * No domain field in LANMAN case. Domain is
+ * returned by old servers in the SMB negprot response
+ *
+ * BB For newer servers which do not support Unicode,
+ * but thus do return domain here, we could add parsing
+ * for it later, but it is not very important
+ */
+ cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
+}
+
+static int
+sess_alloc_buffer(struct sess_data *sess_data, int wct)
+{
+ int rc;
+ struct cifs_ses *ses = sess_data->ses;
+ struct smb_hdr *smb_buf;
+
+ rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+ (void **)&smb_buf);
+
+ if (rc < 0)
+ return rc;
+
+ sess_data->in_len = rc;
+ sess_data->iov[0].iov_base = (char *)smb_buf;
+ sess_data->iov[0].iov_len = sess_data->in_len;
+ /*
+ * This variable will be used to clear the buffer
+ * allocated above in case of any error in the calling function.
+ */
+ sess_data->buf0_type = CIFS_SMALL_BUFFER;
+
+ /* 2000 big enough to fit max user, domain, NOS name etc. */
+ sess_data->iov[2].iov_base = kmalloc(2000, GFP_KERNEL);
+ if (!sess_data->iov[2].iov_base) {
+ rc = -ENOMEM;
+ goto out_free_smb_buf;
+ }
+
+ return 0;
+
+out_free_smb_buf:
+ cifs_small_buf_release(smb_buf);
+ sess_data->iov[0].iov_base = NULL;
+ sess_data->iov[0].iov_len = 0;
+ sess_data->buf0_type = CIFS_NO_BUFFER;
+ return rc;
+}
+
+static void
+sess_free_buffer(struct sess_data *sess_data)
+{
+ struct kvec *iov = sess_data->iov;
+
+ /*
+ * Zero the session data before freeing, as it might contain sensitive info (keys, etc).
+ * Note that iov[1] is already freed by caller.
+ */
+ if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
+ memzero_explicit(iov[0].iov_base, iov[0].iov_len);
+
+ free_rsp_buf(sess_data->buf0_type, iov[0].iov_base);
+ sess_data->buf0_type = CIFS_NO_BUFFER;
+ kfree_sensitive(iov[2].iov_base);
+}
+
+static int
+sess_establish_session(struct sess_data *sess_data)
+{
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+
+ cifs_server_lock(server);
+ if (!server->session_estab) {
+ if (server->sign) {
+ server->session_key.response =
+ kmemdup(ses->auth_key.response,
+ ses->auth_key.len, GFP_KERNEL);
+ if (!server->session_key.response) {
+ cifs_server_unlock(server);
+ return -ENOMEM;
+ }
+ server->session_key.len =
+ ses->auth_key.len;
+ }
+ server->sequence_number = 0x2;
+ server->session_estab = true;
+ }
+ cifs_server_unlock(server);
+
+ cifs_dbg(FYI, "CIFS session established successfully\n");
+ return 0;
+}
+
+static int
+sess_sendreceive(struct sess_data *sess_data)
+{
+ int rc;
+ struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
+ __u16 count;
+ struct kvec rsp_iov = { NULL, 0 };
+
+ count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
+ sess_data->in_len += count;
+ put_bcc(count, smb_buf);
+
+ rc = SendReceive2(sess_data->xid, sess_data->ses,
+ sess_data->iov, 3 /* num_iovecs */,
+ &sess_data->buf0_type,
+ CIFS_LOG_ERROR, &rsp_iov);
+ cifs_small_buf_release(sess_data->iov[0].iov_base);
+ memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
+
+ return rc;
+}
+
+static void
+sess_auth_ntlmv2(struct sess_data *sess_data)
+{
+ int rc = 0;
+ struct smb_hdr *smb_buf;
+ SESSION_SETUP_ANDX *pSMB;
+ char *bcc_ptr;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+ __u32 capabilities;
+ __u16 bytes_remaining;
+
+ /* old style NTLM sessionsetup */
+ /* wct = 13 */
+ rc = sess_alloc_buffer(sess_data, 13);
+ if (rc)
+ goto out;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ bcc_ptr = sess_data->iov[2].iov_base;
+ capabilities = cifs_ssetup_hdr(ses, server, pSMB);
+
+ pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+ /* LM2 password would be here if we supported it */
+ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+
+ if (ses->user_name != NULL) {
+ /* calculate nlmv2 response and session key */
+ rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
+ if (rc) {
+ cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
+ goto out;
+ }
+
+ memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+ ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+ bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
+
+ /* set case sensitive password length after tilen may get
+ * assigned, tilen is 0 otherwise.
+ */
+ pSMB->req_no_secext.CaseSensitivePasswordLength =
+ cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+ } else {
+ pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
+ }
+
+ if (ses->capabilities & CAP_UNICODE) {
+ if (!IS_ALIGNED(sess_data->iov[0].iov_len, 2)) {
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
+ } else {
+ ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
+ }
+
+
+ sess_data->iov[2].iov_len = (long) bcc_ptr -
+ (long) sess_data->iov[2].iov_base;
+
+ rc = sess_sendreceive(sess_data);
+ if (rc)
+ goto out;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
+
+ if (smb_buf->WordCount != 3) {
+ rc = smb_EIO1(smb_eio_trace_sess_nl2_wcc, smb_buf->WordCount);
+ cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
+ goto out;
+ }
+
+ if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
+ cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
+
+ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
+ cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
+
+ bytes_remaining = get_bcc(smb_buf);
+ bcc_ptr = pByteArea(smb_buf);
+
+ /* BB check if Unicode and decode strings */
+ if (bytes_remaining == 0) {
+ /* no string area to decode, do nothing */
+ } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
+ /* unicode string area must be word-aligned */
+ if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
+ ++bcc_ptr;
+ --bytes_remaining;
+ }
+ decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ } else {
+ decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ }
+
+ rc = sess_establish_session(sess_data);
+out:
+ sess_data->result = rc;
+ sess_data->func = NULL;
+ sess_free_buffer(sess_data);
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = NULL;
+}
+
+#ifdef CONFIG_CIFS_UPCALL
+static void
+sess_auth_kerberos(struct sess_data *sess_data)
+{
+ int rc = 0;
+ struct smb_hdr *smb_buf;
+ SESSION_SETUP_ANDX *pSMB;
+ char *bcc_ptr;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+ __u32 capabilities;
+ __u16 bytes_remaining;
+ struct key *spnego_key = NULL;
+ struct cifs_spnego_msg *msg;
+ u16 blob_len;
+
+ /* extended security */
+ /* wct = 12 */
+ rc = sess_alloc_buffer(sess_data, 12);
+ if (rc)
+ goto out;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ bcc_ptr = sess_data->iov[2].iov_base;
+ capabilities = cifs_ssetup_hdr(ses, server, pSMB);
+
+ spnego_key = cifs_get_spnego_key(ses, server);
+ if (IS_ERR(spnego_key)) {
+ rc = PTR_ERR(spnego_key);
+ spnego_key = NULL;
+ goto out;
+ }
+
+ msg = spnego_key->payload.data[0];
+ /*
+ * check version field to make sure that cifs.upcall is
+ * sending us a response in an expected form
+ */
+ if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
+ cifs_dbg(VFS, "incorrect version of cifs.upcall (expected %d but got %d)\n",
+ CIFS_SPNEGO_UPCALL_VERSION, msg->version);
+ rc = -EKEYREJECTED;
+ goto out_put_spnego_key;
+ }
+
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
+ GFP_KERNEL);
+ if (!ses->auth_key.response) {
+ cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
+ msg->sesskey_len);
+ rc = -ENOMEM;
+ goto out_put_spnego_key;
+ }
+ ses->auth_key.len = msg->sesskey_len;
+
+ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ capabilities |= CAP_EXTENDED_SECURITY;
+ pSMB->req.Capabilities = cpu_to_le32(capabilities);
+ sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
+ sess_data->iov[1].iov_len = msg->secblob_len;
+ pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len);
+
+ if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) {
+ /* unicode strings must be word aligned */
+ if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
+ unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
+ } else {
+ ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp);
+ ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
+ }
+
+ sess_data->iov[2].iov_len = (long) bcc_ptr -
+ (long) sess_data->iov[2].iov_base;
+
+ rc = sess_sendreceive(sess_data);
+ if (rc)
+ goto out_put_spnego_key;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
+
+ if (smb_buf->WordCount != 4) {
+ rc = smb_EIO1(smb_eio_trace_sess_krb_wcc, smb_buf->WordCount);
+ cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
+ goto out_put_spnego_key;
+ }
+
+ if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
+ cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
+
+ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
+ cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
+
+ bytes_remaining = get_bcc(smb_buf);
+ bcc_ptr = pByteArea(smb_buf);
+
+ blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+ if (blob_len > bytes_remaining) {
+ cifs_dbg(VFS, "bad security blob length %d\n",
+ blob_len);
+ rc = -EINVAL;
+ goto out_put_spnego_key;
+ }
+ bcc_ptr += blob_len;
+ bytes_remaining -= blob_len;
+
+ /* BB check if Unicode and decode strings */
+ if (bytes_remaining == 0) {
+ /* no string area to decode, do nothing */
+ } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
+ /* unicode string area must be word-aligned */
+ if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
+ ++bcc_ptr;
+ --bytes_remaining;
+ }
+ decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ } else {
+ decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ }
+
+ rc = sess_establish_session(sess_data);
+out_put_spnego_key:
+ key_invalidate(spnego_key);
+ key_put(spnego_key);
+out:
+ sess_data->result = rc;
+ sess_data->func = NULL;
+ sess_free_buffer(sess_data);
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = NULL;
+}
+
+#endif /* ! CONFIG_CIFS_UPCALL */
+
+/*
+ * The required kvec buffers have to be allocated before calling this
+ * function.
+ */
+static int
+_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
+{
+ SESSION_SETUP_ANDX *pSMB;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+ __u32 capabilities;
+ char *bcc_ptr;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+
+ capabilities = cifs_ssetup_hdr(ses, server, pSMB);
+ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ capabilities |= CAP_EXTENDED_SECURITY;
+ pSMB->req.Capabilities |= cpu_to_le32(capabilities);
+
+ bcc_ptr = sess_data->iov[2].iov_base;
+
+ if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) {
+ /* unicode strings must be word aligned */
+ if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
+ } else {
+ ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp);
+ }
+
+ sess_data->iov[2].iov_len = (long) bcc_ptr -
+ (long) sess_data->iov[2].iov_base;
+
+ return 0;
+}
+
+static void
+sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data);
+
+static void
+sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
+{
+ int rc;
+ struct smb_hdr *smb_buf;
+ SESSION_SETUP_ANDX *pSMB;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+ __u16 bytes_remaining;
+ char *bcc_ptr;
+ unsigned char *ntlmsspblob = NULL;
+ u16 blob_len;
+
+ cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
+
+ /*
+ * if memory allocation is successful, caller of this function
+ * frees it.
+ */
+ ses->ntlmssp = kmalloc_obj(struct ntlmssp_auth);
+ if (!ses->ntlmssp) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ ses->ntlmssp->sesskey_per_smbsess = false;
+
+ /* wct = 12 */
+ rc = sess_alloc_buffer(sess_data, 12);
+ if (rc)
+ goto out;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+
+ /* Build security blob before we assemble the request */
+ rc = build_ntlmssp_negotiate_blob(&ntlmsspblob,
+ &blob_len, ses, server,
+ sess_data->nls_cp);
+ if (rc)
+ goto out_free_ntlmsspblob;
+
+ sess_data->iov[1].iov_len = blob_len;
+ sess_data->iov[1].iov_base = ntlmsspblob;
+ pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
+
+ rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
+ if (rc)
+ goto out_free_ntlmsspblob;
+
+ rc = sess_sendreceive(sess_data);
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
+
+ /* If true, rc here is expected and not an error */
+ if (sess_data->buf0_type != CIFS_NO_BUFFER &&
+ smb_buf->Status.CifsError ==
+ cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
+ rc = 0;
+
+ if (rc)
+ goto out_free_ntlmsspblob;
+
+ cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
+
+ if (smb_buf->WordCount != 4) {
+ rc = smb_EIO1(smb_eio_trace_sess_rawnl_neg_wcc, smb_buf->WordCount);
+ cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
+ goto out_free_ntlmsspblob;
+ }
+
+ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
+ cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
+
+ bytes_remaining = get_bcc(smb_buf);
+ bcc_ptr = pByteArea(smb_buf);
+
+ blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+ if (blob_len > bytes_remaining) {
+ cifs_dbg(VFS, "bad security blob length %d\n",
+ blob_len);
+ rc = -EINVAL;
+ goto out_free_ntlmsspblob;
+ }
+
+ rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
+
+out_free_ntlmsspblob:
+ kfree_sensitive(ntlmsspblob);
+out:
+ sess_free_buffer(sess_data);
+
+ if (!rc) {
+ sess_data->func = sess_auth_rawntlmssp_authenticate;
+ return;
+ }
+
+ /* Else error. Cleanup */
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = NULL;
+ kfree_sensitive(ses->ntlmssp);
+ ses->ntlmssp = NULL;
+
+ sess_data->func = NULL;
+ sess_data->result = rc;
+}
+
+static void
+sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
+{
+ int rc;
+ struct smb_hdr *smb_buf;
+ SESSION_SETUP_ANDX *pSMB;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+ __u16 bytes_remaining;
+ char *bcc_ptr;
+ unsigned char *ntlmsspblob = NULL;
+ u16 blob_len;
+
+ cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
+
+ /* wct = 12 */
+ rc = sess_alloc_buffer(sess_data, 12);
+ if (rc)
+ goto out;
+
+ /* Build security blob before we assemble the request */
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ smb_buf = (struct smb_hdr *)pSMB;
+ rc = build_ntlmssp_auth_blob(&ntlmsspblob,
+ &blob_len, ses, server,
+ sess_data->nls_cp);
+ if (rc)
+ goto out_free_ntlmsspblob;
+ sess_data->iov[1].iov_len = blob_len;
+ sess_data->iov[1].iov_base = ntlmsspblob;
+ pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
+ /*
+ * Make sure that we tell the server that we are using
+ * the uid that it just gave us back on the response
+ * (challenge)
+ */
+ smb_buf->Uid = ses->Suid;
+
+ rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
+ if (rc)
+ goto out_free_ntlmsspblob;
+
+ rc = sess_sendreceive(sess_data);
+ if (rc)
+ goto out_free_ntlmsspblob;
+
+ pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
+ smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
+ if (smb_buf->WordCount != 4) {
+ rc = smb_EIO1(smb_eio_trace_sess_rawnl_auth_wcc, smb_buf->WordCount);
+ cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
+ goto out_free_ntlmsspblob;
+ }
+
+ if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
+ cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
+
+ if (ses->Suid != smb_buf->Uid) {
+ ses->Suid = smb_buf->Uid;
+ cifs_dbg(FYI, "UID changed! new UID = %llu\n", ses->Suid);
+ }
+
+ bytes_remaining = get_bcc(smb_buf);
+ bcc_ptr = pByteArea(smb_buf);
+ blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+ if (blob_len > bytes_remaining) {
+ cifs_dbg(VFS, "bad security blob length %d\n",
+ blob_len);
+ rc = -EINVAL;
+ goto out_free_ntlmsspblob;
+ }
+ bcc_ptr += blob_len;
+ bytes_remaining -= blob_len;
+
+
+ /* BB check if Unicode and decode strings */
+ if (bytes_remaining == 0) {
+ /* no string area to decode, do nothing */
+ } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
+ /* unicode string area must be word-aligned */
+ if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
+ ++bcc_ptr;
+ --bytes_remaining;
+ }
+ decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ } else {
+ decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
+ sess_data->nls_cp);
+ }
+
+out_free_ntlmsspblob:
+ kfree_sensitive(ntlmsspblob);
+out:
+ sess_free_buffer(sess_data);
+
+ if (!rc)
+ rc = sess_establish_session(sess_data);
+
+ /* Cleanup */
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = NULL;
+ kfree_sensitive(ses->ntlmssp);
+ ses->ntlmssp = NULL;
+
+ sess_data->func = NULL;
+ sess_data->result = rc;
+}
+
+static int select_sec(struct sess_data *sess_data)
+{
+ int type;
+ struct cifs_ses *ses = sess_data->ses;
+ struct TCP_Server_Info *server = sess_data->server;
+
+ type = cifs_select_sectype(server, ses->sectype);
+ cifs_dbg(FYI, "sess setup type %d\n", type);
+ if (type == Unspecified) {
+ cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case NTLMv2:
+ sess_data->func = sess_auth_ntlmv2;
+ break;
+ case Kerberos:
+#ifdef CONFIG_CIFS_UPCALL
+ sess_data->func = sess_auth_kerberos;
+ break;
+#else
+ cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
+ return -ENOSYS;
+#endif /* CONFIG_CIFS_UPCALL */
+ case RawNTLMSSP:
+ sess_data->func = sess_auth_rawntlmssp_negotiate;
+ break;
+ default:
+ cifs_dbg(VFS, "secType %d not supported!\n", type);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ const struct nls_table *nls_cp)
+{
+ int rc = 0;
+ struct sess_data *sess_data;
+
+ if (ses == NULL) {
+ WARN(1, "%s: ses == NULL!", __func__);
+ return -EINVAL;
+ }
+
+ sess_data = kzalloc_obj(struct sess_data);
+ if (!sess_data)
+ return -ENOMEM;
+
+ sess_data->xid = xid;
+ sess_data->ses = ses;
+ sess_data->server = server;
+ sess_data->buf0_type = CIFS_NO_BUFFER;
+ sess_data->nls_cp = (struct nls_table *) nls_cp;
+
+ rc = select_sec(sess_data);
+ if (rc)
+ goto out;
+
+ while (sess_data->func)
+ sess_data->func(sess_data);
+
+ /* Store result before we free sess_data */
+ rc = sess_data->result;
+
+out:
+ kfree_sensitive(sess_data);
+ return rc;
+}
diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c
new file mode 100644
index 000000000000..53abb29fe71b
--- /dev/null
+++ b/fs/smb/client/smb1transport.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2008
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ * Jeremy Allison (jra@samba.org) 2006.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/gfp.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/tcp.h>
+#include <linux/bvec.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include <linux/processor.h>
+#include <linux/mempool.h>
+#include <linux/sched/signal.h>
+#include <linux/task_io_accounting_ops.h>
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "smb1proto.h"
+#include "smb2proto.h"
+#include "cifs_debug.h"
+#include "smbdirect.h"
+#include "compress.h"
+
+/* Max number of iovectors we can use off the stack when sending requests. */
+#define CIFS_MAX_IOV_SIZE 8
+
+static struct mid_q_entry *
+alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
+{
+ struct mid_q_entry *temp;
+
+ if (server == NULL) {
+ cifs_dbg(VFS, "%s: null TCP session\n", __func__);
+ return NULL;
+ }
+
+ temp = mempool_alloc(&cifs_mid_pool, GFP_NOFS);
+ memset(temp, 0, sizeof(struct mid_q_entry));
+ refcount_set(&temp->refcount, 1);
+ spin_lock_init(&temp->mid_lock);
+ temp->mid = get_mid(smb_buffer);
+ temp->pid = current->pid;
+ temp->command = cpu_to_le16(smb_buffer->Command);
+ cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
+ /* easier to use jiffies */
+ /* when mid allocated can be before when sent */
+ temp->when_alloc = jiffies;
+
+ /*
+ * The default is for the mid to be synchronous, so the
+ * default callback just wakes up the current task.
+ */
+ get_task_struct(current);
+ temp->creator = current;
+ temp->callback = cifs_wake_up_task;
+ temp->callback_data = current;
+
+ atomic_inc(&mid_count);
+ temp->mid_state = MID_REQUEST_ALLOCATED;
+ return temp;
+}
+
+static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
+ struct mid_q_entry **ppmidQ)
+{
+ spin_lock(&ses->ses_lock);
+ if (ses->ses_status == SES_NEW) {
+ if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
+ (in_buf->Command != SMB_COM_NEGOTIATE)) {
+ spin_unlock(&ses->ses_lock);
+ return -EAGAIN;
+ }
+ /* else ok - we are setting up session */
+ }
+
+ if (ses->ses_status == SES_EXITING) {
+ /* check if SMB session is bad because we are setting it up */
+ if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
+ spin_unlock(&ses->ses_lock);
+ return -EAGAIN;
+ }
+ /* else ok - we are shutting down session */
+ }
+ spin_unlock(&ses->ses_lock);
+
+ *ppmidQ = alloc_mid(in_buf, ses->server);
+ if (*ppmidQ == NULL)
+ return -ENOMEM;
+ spin_lock(&ses->server->mid_queue_lock);
+ list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
+ spin_unlock(&ses->server->mid_queue_lock);
+ return 0;
+}
+
+struct mid_q_entry *
+cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+{
+ int rc;
+ struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+ struct mid_q_entry *mid;
+
+ /* enable signing if server requires it */
+ if (server->sign)
+ hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ mid = alloc_mid(hdr, server);
+ if (mid == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
+ if (rc) {
+ release_mid(server, mid);
+ return ERR_PTR(rc);
+ }
+
+ return mid;
+}
+
+/*
+ *
+ * Send an SMB Request. No response info (other than return code)
+ * needs to be parsed.
+ *
+ * flags indicate the type of request buffer and how long to wait
+ * and whether to log NT STATUS code (error) before mapping it to POSIX error
+ *
+ */
+int
+SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
+ char *in_buf, unsigned int in_len, int flags)
+{
+ int rc;
+ struct kvec iov[1];
+ struct kvec rsp_iov;
+ int resp_buf_type;
+
+ iov[0].iov_base = in_buf;
+ iov[0].iov_len = in_len;
+ flags |= CIFS_NO_RSP_BUF;
+ rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+ cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
+
+ return rc;
+}
+
+int
+cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+ bool log_error)
+{
+ unsigned int len = mid->response_pdu_len;
+
+ dump_smb(mid->resp_buf, min_t(u32, 92, len));
+
+ /* convert the length into a more usable form */
+ if (server->sign) {
+ struct kvec iov[1];
+ int rc = 0;
+ struct smb_rqst rqst = { .rq_iov = iov,
+ .rq_nvec = ARRAY_SIZE(iov) };
+
+ iov[0].iov_base = mid->resp_buf;
+ iov[0].iov_len = len;
+
+ rc = cifs_verify_signature(&rqst, server,
+ mid->sequence_number);
+ if (rc) {
+ cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
+ rc);
+
+ if (!(server->sec_mode & SECMODE_SIGN_REQUIRED)) {
+ cifs_reconnect(server, true);
+ return rc;
+ }
+ }
+ }
+
+ /* BB special case reconnect tid and uid here? */
+ return map_and_check_smb_error(server, mid, log_error);
+}
+
+struct mid_q_entry *
+cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst)
+{
+ int rc;
+ struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+ struct mid_q_entry *mid;
+
+ rc = allocate_mid(ses, hdr, &mid);
+ if (rc)
+ return ERR_PTR(rc);
+ rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
+ if (rc) {
+ delete_mid(server, mid);
+ return ERR_PTR(rc);
+ }
+ return mid;
+}
+
+int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
+ struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
+ const int flags, struct kvec *resp_iov)
+{
+ struct smb_rqst rqst = {
+ .rq_iov = iov,
+ .rq_nvec = n_vec,
+ };
+
+ return cifs_send_recv(xid, ses, ses->server,
+ &rqst, resp_buf_type, flags, resp_iov);
+}
+
+int
+SendReceive(const unsigned int xid, struct cifs_ses *ses,
+ struct smb_hdr *in_buf, unsigned int in_len,
+ struct smb_hdr *out_buf, int *pbytes_returned, const int flags)
+{
+ struct TCP_Server_Info *server;
+ struct kvec resp_iov = {};
+ struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
+ struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
+ int resp_buf_type;
+ int rc = 0;
+
+ if (WARN_ON_ONCE(in_len > 0xffffff))
+ return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
+ if (ses == NULL) {
+ cifs_dbg(VFS, "Null smb session\n");
+ return smb_EIO(smb_eio_trace_null_pointers);
+ }
+ server = ses->server;
+ if (server == NULL) {
+ cifs_dbg(VFS, "Null tcp session\n");
+ return smb_EIO(smb_eio_trace_null_pointers);
+ }
+
+ /* Ensure that we do not send more than 50 overlapping requests
+ to the same server. We may make this configurable later or
+ use ses->maxReq */
+
+ if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+ cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
+ in_len);
+ return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
+ }
+
+ rc = cifs_send_recv(xid, ses, ses->server,
+ &rqst, &resp_buf_type, flags, &resp_iov);
+ if (rc < 0)
+ goto out;
+
+ if (out_buf) {
+ *pbytes_returned = resp_iov.iov_len;
+ if (resp_iov.iov_len)
+ memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
+ }
+
+out:
+ free_rsp_buf(resp_buf_type, resp_iov.iov_base);
+ return rc;
+}
+
+/*
+ return codes:
+ 0 not a transact2, or all data present
+ >0 transact2 with that much data missing
+ -EINVAL invalid transact2
+ */
+static int
+check2ndT2(char *buf)
+{
+ struct smb_hdr *pSMB = (struct smb_hdr *)buf;
+ struct smb_t2_rsp *pSMBt;
+ int remaining;
+ __u16 total_data_size, data_in_this_rsp;
+
+ if (pSMB->Command != SMB_COM_TRANSACTION2)
+ return 0;
+
+ /* check for plausible wct, bcc and t2 data and parm sizes */
+ /* check for parm and data offset going beyond end of smb */
+ if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+ cifs_dbg(FYI, "Invalid transact2 word count\n");
+ return -EINVAL;
+ }
+
+ pSMBt = (struct smb_t2_rsp *)pSMB;
+
+ total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+ data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+ if (total_data_size == data_in_this_rsp)
+ return 0;
+ else if (total_data_size < data_in_this_rsp) {
+ cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
+ total_data_size, data_in_this_rsp);
+ return -EINVAL;
+ }
+
+ remaining = total_data_size - data_in_this_rsp;
+
+ cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
+ remaining);
+ if (total_data_size > CIFSMaxBufSize) {
+ cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
+ total_data_size, CIFSMaxBufSize);
+ return -EINVAL;
+ }
+ return remaining;
+}
+
+static int
+coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
+{
+ struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
+ struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
+ char *data_area_of_tgt;
+ char *data_area_of_src;
+ int remaining;
+ unsigned int byte_count, total_in_tgt;
+ __u16 tgt_total_cnt, src_total_cnt, total_in_src;
+
+ src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
+ tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+
+ if (tgt_total_cnt != src_total_cnt)
+ cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
+ src_total_cnt, tgt_total_cnt);
+
+ total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+ remaining = tgt_total_cnt - total_in_tgt;
+
+ if (remaining < 0) {
+ cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
+ tgt_total_cnt, total_in_tgt);
+ return -EPROTO;
+ }
+
+ if (remaining == 0) {
+ /* nothing to do, ignore */
+ cifs_dbg(FYI, "no more data remains\n");
+ return 0;
+ }
+
+ total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
+ if (remaining < total_in_src)
+ cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
+
+ /* find end of first SMB data area */
+ data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
+ get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
+
+ /* validate target area */
+ data_area_of_src = (char *)&pSMBs->hdr.Protocol +
+ get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
+
+ data_area_of_tgt += total_in_tgt;
+
+ total_in_tgt += total_in_src;
+ /* is the result too big for the field? */
+ if (total_in_tgt > USHRT_MAX) {
+ cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
+ total_in_tgt);
+ return -EPROTO;
+ }
+ put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
+
+ /* fix up the BCC */
+ byte_count = get_bcc(target_hdr);
+ byte_count += total_in_src;
+ /* is the result too big for the field? */
+ if (byte_count > USHRT_MAX) {
+ cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
+ return -EPROTO;
+ }
+ put_bcc(byte_count, target_hdr);
+
+ byte_count = *pdu_len;
+ byte_count += total_in_src;
+ /* don't allow buffer to overflow */
+ if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+ cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
+ byte_count);
+ return -ENOBUFS;
+ }
+ *pdu_len = byte_count;
+
+ /* copy second buffer into end of first buffer */
+ memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
+
+ if (remaining != total_in_src) {
+ /* more responses to go */
+ cifs_dbg(FYI, "waiting for more secondary responses\n");
+ return 1;
+ }
+
+ /* we are done */
+ cifs_dbg(FYI, "found the last secondary response\n");
+ return 0;
+}
+
+bool
+cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+ char *buf, int malformed)
+{
+ if (malformed)
+ return false;
+ if (check2ndT2(buf) <= 0)
+ return false;
+ mid->multiRsp = true;
+ if (mid->resp_buf) {
+ /* merge response - fix up 1st*/
+ malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
+ if (malformed > 0)
+ return true;
+ /* All parts received or packet is malformed. */
+ mid->multiEnd = true;
+ dequeue_mid(server, mid, malformed);
+ return true;
+ }
+ if (!server->large_buf) {
+ /*FIXME: switch to already allocated largebuf?*/
+ cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
+ } else {
+ /* Have first buffer */
+ mid->resp_buf = buf;
+ mid->large_buf = true;
+ server->bigbuf = NULL;
+ }
+ return true;
+}
+
+static int
+check_smb_hdr(struct smb_hdr *smb)
+{
+ /* does it have the right SMB "signature" ? */
+ if (*(__le32 *) smb->Protocol != SMB1_PROTO_NUMBER) {
+ cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n",
+ *(unsigned int *)smb->Protocol);
+ return 1;
+ }
+
+ /* if it's a response then accept */
+ if (smb->Flags & SMBFLG_RESPONSE)
+ return 0;
+
+ /* only one valid case where server sends us request */
+ if (smb->Command == SMB_COM_LOCKING_ANDX)
+ return 0;
+
+ /*
+ * Windows NT server returns error response (e.g. STATUS_DELETE_PENDING
+ * or STATUS_OBJECT_NAME_NOT_FOUND or ERRDOS/ERRbadfile or any other)
+ * for some TRANS2 requests without the RESPONSE flag set in header.
+ */
+ if (smb->Command == SMB_COM_TRANSACTION2 && smb->Status.CifsError != 0)
+ return 0;
+
+ cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
+ get_mid(smb));
+ return 1;
+}
+
+int
+checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read,
+ struct TCP_Server_Info *server)
+{
+ struct smb_hdr *smb = (struct smb_hdr *)buf;
+ __u32 rfclen = pdu_len;
+ __u32 clc_len; /* calculated length */
+ cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
+ total_read, rfclen);
+
+ /* is this frame too small to even get to a BCC? */
+ if (total_read < 2 + sizeof(struct smb_hdr)) {
+ if ((total_read >= sizeof(struct smb_hdr) - 1)
+ && (smb->Status.CifsError != 0)) {
+ /* it's an error return */
+ smb->WordCount = 0;
+ /* some error cases do not return wct and bcc */
+ return 0;
+ } else if ((total_read == sizeof(struct smb_hdr) + 1) &&
+ (smb->WordCount == 0)) {
+ char *tmp = (char *)smb;
+ /* Need to work around a bug in two servers here */
+ /* First, check if the part of bcc they sent was zero */
+ if (tmp[sizeof(struct smb_hdr)] == 0) {
+ /* some servers return only half of bcc
+ * on simple responses (wct, bcc both zero)
+ * in particular have seen this on
+ * ulogoffX and FindClose. This leaves
+ * one byte of bcc potentially uninitialized
+ */
+ /* zero rest of bcc */
+ tmp[sizeof(struct smb_hdr)+1] = 0;
+ return 0;
+ }
+ cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
+ return smb_EIO1(smb_eio_trace_rx_inv_bcc, tmp[sizeof(struct smb_hdr)]);
+ } else {
+ cifs_dbg(VFS, "Length less than smb header size\n");
+ return smb_EIO2(smb_eio_trace_rx_too_short,
+ total_read, smb->WordCount);
+ }
+ } else if (total_read < sizeof(*smb) + 2 * smb->WordCount) {
+ cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
+ __func__, smb->WordCount);
+ return smb_EIO2(smb_eio_trace_rx_check_rsp,
+ total_read, 2 + sizeof(struct smb_hdr));
+ }
+
+ /* otherwise, there is enough to get to the BCC */
+ if (check_smb_hdr(smb))
+ return smb_EIO1(smb_eio_trace_rx_rfc1002_magic, *(u32 *)smb->Protocol);
+ clc_len = smbCalcSize(smb);
+
+ if (rfclen != total_read) {
+ cifs_dbg(VFS, "Length read does not match RFC1001 length %d/%d\n",
+ rfclen, total_read);
+ return smb_EIO2(smb_eio_trace_rx_check_rsp,
+ total_read, rfclen);
+ }
+
+ if (rfclen != clc_len) {
+ __u16 mid = get_mid(smb);
+ /* check if bcc wrapped around for large read responses */
+ if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
+ /* check if lengths match mod 64K */
+ if (((rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
+ return 0; /* bcc wrapped */
+ }
+ cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
+ clc_len, rfclen, mid);
+
+ if (rfclen < clc_len) {
+ cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
+ rfclen, mid);
+ return smb_EIO2(smb_eio_trace_rx_calc_len_too_big,
+ rfclen, clc_len);
+ } else if (rfclen > clc_len + 512) {
+ /*
+ * Some servers (Windows XP in particular) send more
+ * data than the lengths in the SMB packet would
+ * indicate on certain calls (byte range locks and
+ * trans2 find first calls in particular). While the
+ * client can handle such a frame by ignoring the
+ * trailing data, we choose limit the amount of extra
+ * data to 512 bytes.
+ */
+ cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
+ rfclen, mid);
+ return smb_EIO2(smb_eio_trace_rx_overlong,
+ rfclen, clc_len + 512);
+ }
+ }
+ return 0;
+}
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index a7f629238830..b292aa94a593 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -13,7 +13,6 @@
#include <linux/pagemap.h>
#include <asm/div64.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -22,15 +21,17 @@
#include "fscache.h"
#include "smb2proto.h"
#include "../common/smb2status.h"
+#include "../common/smbfsctl.h"
static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
{
struct smb2_err_rsp *err = iov->iov_base;
struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL);
+ u8 *end = (u8 *)err + iov->iov_len;
u32 len;
if (err->ErrorContextCount) {
- struct smb2_error_context_rsp *p, *end;
+ struct smb2_error_context_rsp *p;
len = (u32)err->ErrorContextCount * (offsetof(struct smb2_error_context_rsp,
ErrorContextData) +
@@ -39,8 +40,7 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
return ERR_PTR(-EINVAL);
p = (struct smb2_error_context_rsp *)err->ErrorData;
- end = (struct smb2_error_context_rsp *)((u8 *)err + iov->iov_len);
- do {
+ while ((u8 *)p + sizeof(*p) <= end) {
if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) {
sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData;
break;
@@ -50,14 +50,16 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
- } while (p < end);
+ }
} else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) {
sym = (struct smb2_symlink_err_rsp *)err->ErrorData;
}
- if (!IS_ERR(sym) && (le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
- le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK))
+ if (!IS_ERR(sym) &&
+ ((u8 *)sym + sizeof(*sym) > end ||
+ le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
+ le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK))
sym = ERR_PTR(-EINVAL);
return sym;
@@ -72,15 +74,15 @@ int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_i
* POSIX server does not distinguish between symlinks to file and
* symlink directory. So nothing is needed to fix on the client side.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)
return 0;
if (!*target)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
len = strlen(*target);
if (!len)
- return -EIO;
+ return smb_EIO1(smb_eio_trace_sym_target_len, len);
/*
* If this is directory symlink and it does not have trailing slash then
@@ -104,7 +106,7 @@ int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_i
* both Windows and Linux systems. So return an error for such symlink.
*/
if (!directory && (*target)[len-1] == '/')
- return -EIO;
+ return smb_EIO(smb_eio_trace_sym_slash);
return 0;
}
@@ -128,8 +130,10 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
print_len = le16_to_cpu(sym->PrintNameLength);
print_offs = le16_to_cpu(sym->PrintNameOffset);
- if (iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offs + sub_len ||
- iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offs + print_len)
+ if ((char *)sym->PathBuffer + sub_offs + sub_len >
+ (char *)iov->iov_base + iov->iov_len ||
+ (char *)sym->PathBuffer + print_offs + print_len >
+ (char *)iov->iov_base + iov->iov_len)
return -EINVAL;
return smb2_parse_native_symlink(path,
@@ -140,7 +144,8 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
cifs_sb);
}
-int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, void *buf)
+int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
+ __u32 *oplock, void *buf)
{
int rc;
__le16 *smb2_path;
@@ -177,6 +182,9 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
&err_buftype);
if (rc == -EACCES && retry_without_read_attributes) {
+ free_rsp_buf(err_buftype, err_iov.iov_base);
+ memset(&err_iov, 0, sizeof(err_iov));
+ err_buftype = CIFS_NO_BUFFER;
oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
&err_buftype);
@@ -277,7 +285,7 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
max_num = max_buf / sizeof(struct smb2_lock_element);
- buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
+ buf = kzalloc_objs(struct smb2_lock_element, max_num);
if (!buf)
return -ENOMEM;
@@ -420,7 +428,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
max_num = max_buf / sizeof(struct smb2_lock_element);
- buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
+ buf = kzalloc_objs(struct smb2_lock_element, max_num);
if (!buf) {
free_xid(xid);
return -ENOMEM;
diff --git a/fs/smb/client/smb2glob.h b/fs/smb/client/smb2glob.h
index 224495322a05..19da74b1edab 100644
--- a/fs/smb/client/smb2glob.h
+++ b/fs/smb/client/smb2glob.h
@@ -30,10 +30,9 @@ enum smb2_compound_ops {
SMB2_OP_QUERY_DIR,
SMB2_OP_MKDIR,
SMB2_OP_RENAME,
- SMB2_OP_DELETE,
SMB2_OP_HARDLINK,
SMB2_OP_SET_EOF,
- SMB2_OP_RMDIR,
+ SMB2_OP_UNLINK,
SMB2_OP_POSIX_QUERY_INFO,
SMB2_OP_SET_REPARSE,
SMB2_OP_GET_REPARSE,
@@ -47,4 +46,16 @@ enum smb2_compound_ops {
#define END_OF_CHAIN 4
#define RELATED_REQUEST 8
+/*
+ *****************************************************************
+ * Struct definitions go here
+ *****************************************************************
+ */
+
+struct status_to_posix_error {
+ __u32 smb2_status;
+ int posix_error;
+ char *status_string;
+};
+
#endif /* _SMB2_GLOB_H */
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 57d9bfbadd97..c6dd282fc3a9 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -13,7 +13,6 @@
#include <linux/pagemap.h>
#include <asm/div64.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -21,26 +20,30 @@
#include "cifs_unicode.h"
#include "fscache.h"
#include "smb2glob.h"
-#include "smb2pdu.h"
#include "smb2proto.h"
#include "cached_dir.h"
#include "../common/smb2status.h"
+#include "../common/smbfsctl.h"
static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
{
struct reparse_data_buffer *buf;
struct smb2_ioctl_rsp *io = iov->iov_base;
u32 off, count, len;
+ u16 rdlen;
count = le32_to_cpu(io->OutputCount);
off = le32_to_cpu(io->OutputOffset);
if (check_add_overflow(off, count, &len) || len > iov->iov_len)
- return ERR_PTR(-EIO);
+ return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_overlong,
+ off, count));
buf = (struct reparse_data_buffer *)((u8 *)io + off);
len = sizeof(*buf);
- if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
- return ERR_PTR(-EIO);
+ rdlen = le16_to_cpu(buf->ReparseDataLength);
+
+ if (count < len || count < rdlen + len)
+ return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, rdlen));
return buf;
}
@@ -50,7 +53,7 @@ static inline __u32 file_create_options(struct dentry *dentry)
if (dentry) {
ci = CIFS_I(d_inode(dentry));
- if (ci->cifsAttrs & ATTR_REPARSE)
+ if (ci->cifsAttrs & ATTR_REPARSE_POINT)
return OPEN_REPARSE_POINT;
}
return 0;
@@ -125,7 +128,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
nlen = ea->ea_name_length;
vlen = le16_to_cpu(ea->ea_value_length);
if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
- (u8 *)ea + nlen + 1 + vlen > end)
+ (u8 *)ea->ea_data + nlen + 1 + vlen > end)
return -EINVAL;
switch (vlen) {
@@ -162,6 +165,27 @@ static int check_wsl_eas(struct kvec *rsp_iov)
}
/*
+ * If @cfile is NULL, then need to account for trailing CLOSE request in the
+ * compound chain.
+ */
+static void set_next_compound(struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile,
+ int i, int num_cmds,
+ struct smb_rqst *rqst, int *num_rqst)
+{
+ int k = !cfile ? 1 : 0;
+
+ if (i + 1 < num_cmds + k)
+ smb2_set_next_command(tcon, &rqst[*num_rqst]);
+ if (i + k > 0)
+ smb2_set_related(&rqst[*num_rqst]);
+ (*num_rqst)++;
+}
+
+#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID)
+#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID)
+
+/*
* note: If cfile is passed, the reference to it is dropped here.
* So make sure that you do not reuse cfile after return from this func.
*
@@ -185,7 +209,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
struct reparse_data_buffer *rbuf;
struct TCP_Server_Info *server;
int resp_buftype[MAX_COMPOUND];
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
__u8 delete_pending[8] = {1,};
struct kvec *rsp_iov, *iov;
struct inode *inode = NULL;
@@ -206,9 +230,11 @@ replay_again:
num_rqst = 0;
server = cifs_pick_channel(ses);
- vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
- if (vars == NULL)
- return -ENOMEM;
+ vars = kzalloc_obj(*vars, GFP_ATOMIC);
+ if (vars == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
rqst = &vars->rqst[0];
rsp_iov = &vars->rsp_iov[0];
@@ -279,32 +305,16 @@ replay_again:
rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FILE_ALL_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb2_file_all_info) +
- PATH_MAX * 2, 0, NULL);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- FILE_ALL_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb2_file_all_info) +
- PATH_MAX * 2, 0, NULL);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FILE_ALL_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ sizeof(struct smb2_file_all_info) +
+ PATH_MAX * 2, 0, NULL);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_query_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
@@ -312,41 +322,21 @@ replay_again:
rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- /* TBD: fix following to allow for longer SIDs */
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- SMB_FIND_FILE_POSIX_INFO,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo *) +
- (PATH_MAX * 2) +
- (sizeof(struct smb_sid) * 2), 0, NULL);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- SMB_FIND_FILE_POSIX_INFO,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo *) +
- (PATH_MAX * 2) +
- (sizeof(struct smb_sid) * 2), 0, NULL);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ /* TBD: fix following to allow for longer SIDs */
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ SMB_FIND_FILE_POSIX_INFO,
+ SMB2_O_INFO_FILE, 0,
+ sizeof(struct smb311_posix_qinfo) +
+ (PATH_MAX * 2) +
+ (sizeof(struct smb_sid) * 2), 0, NULL);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
- case SMB2_OP_DELETE:
- trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path);
- break;
case SMB2_OP_MKDIR:
/*
* Directories are created through parameters in the
@@ -354,23 +344,23 @@ replay_again:
*/
trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path);
break;
- case SMB2_OP_RMDIR:
- rqst[num_rqst].rq_iov = &vars->si_iov[0];
+ case SMB2_OP_UNLINK:
+ rqst[num_rqst].rq_iov = vars->unlink_iov;
rqst[num_rqst].rq_nvec = 1;
size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
data[0] = &delete_pending[0];
rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst], COMPOUND_FID,
- COMPOUND_FID, current->tgid,
- FILE_DISPOSITION_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_DISPOSITION_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ data, size);
if (rc)
goto finished;
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst++]);
- trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path);
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
+ trace_smb3_unlink_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_EOF:
rqst[num_rqst].rq_iov = &vars->si_iov[0];
@@ -379,32 +369,15 @@ replay_again:
size[0] = in_iov[i].iov_len;
data[0] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- current->tgid,
- FILE_END_OF_FILE_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- current->tgid,
- FILE_END_OF_FILE_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_END_OF_FILE_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ data, size);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_INFO:
@@ -414,33 +387,19 @@ replay_again:
size[0] = in_iov[i].iov_len;
data[0] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid, current->tgid,
- FILE_BASIC_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID, current->tgid,
- FILE_BASIC_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_BASIC_INFORMATION,
+ SMB2_O_INFO_FILE, 0, data, size);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
case SMB2_OP_RENAME:
- rqst[num_rqst].rq_iov = &vars->si_iov[0];
+ rqst[num_rqst].rq_iov = vars->rename_iov;
rqst[num_rqst].rq_nvec = 2;
len = in_iov[i].iov_len;
@@ -455,31 +414,19 @@ replay_again:
size[1] = len + 2 /* null */;
data[1] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- current->tgid, FILE_RENAME_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- current->tgid, FILE_RENAME_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_RENAME_INFORMATION,
+ SMB2_O_INFO_FILE, 0, data, size);
+
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_HARDLINK:
- rqst[num_rqst].rq_iov = &vars->si_iov[0];
+ rqst[num_rqst].rq_iov = vars->hl_iov;
rqst[num_rqst].rq_nvec = 2;
len = in_iov[i].iov_len;
@@ -495,41 +442,27 @@ replay_again:
data[1] = in_iov[i].iov_base;
rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst], COMPOUND_FID,
- COMPOUND_FID, current->tgid,
- FILE_LINK_INFORMATION,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_LINK_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size);
if (rc)
goto finished;
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst++]);
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_REPARSE:
rqst[num_rqst].rq_iov = vars->io_iov;
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
- if (cfile) {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FSCTL_SET_REPARSE_POINT,
- in_iov[i].iov_base,
- in_iov[i].iov_len, 0);
- } else {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- FSCTL_SET_REPARSE_POINT,
- in_iov[i].iov_base,
- in_iov[i].iov_len, 0);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FSCTL_SET_REPARSE_POINT,
+ in_iov[i].iov_base,
+ in_iov[i].iov_len, 0);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
@@ -537,25 +470,13 @@ replay_again:
rqst[num_rqst].rq_iov = vars->io_iov;
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
- if (cfile) {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FSCTL_GET_REPARSE_POINT,
- NULL, 0, CIFSMaxBufSize);
- } else {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- FSCTL_GET_REPARSE_POINT,
- NULL, 0, CIFSMaxBufSize);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FSCTL_GET_REPARSE_POINT,
+ NULL, 0, CIFSMaxBufSize);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
@@ -563,34 +484,17 @@ replay_again:
rqst[num_rqst].rq_iov = &vars->ea_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FILE_FULL_EA_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
- sizeof(wsl_query_eas),
- (void *)wsl_query_eas);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- FILE_FULL_EA_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
- sizeof(wsl_query_eas),
- (void *)wsl_query_eas);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FILE_FULL_EA_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
+ sizeof(wsl_query_eas),
+ (void *)wsl_query_eas);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_query_wsl_ea_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
@@ -619,18 +523,26 @@ replay_again:
num_rqst++;
if (cfile) {
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
for (i = 1; i < num_rqst - 2; i++)
smb2_set_replay(server, &rqst[i]);
+ }
rc = compound_send_recv(xid, ses, server,
flags, num_rqst - 2,
&rqst[1], &resp_buftype[1],
&rsp_iov[1]);
} else {
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
for (i = 0; i < num_rqst; i++)
smb2_set_replay(server, &rqst[i]);
+ }
rc = compound_send_recv(xid, ses, server,
flags, num_rqst,
@@ -660,16 +572,18 @@ finished:
idata->fi.EndOfFile = create_rsp->EndofFile;
if (le32_to_cpu(idata->fi.NumberOfLinks) == 0)
idata->fi.NumberOfLinks = cpu_to_le32(1); /* dummy value */
- idata->fi.DeletePending = 0;
+ idata->fi.DeletePending = 0; /* successful open = not delete pending */
idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
/* smb2_parse_contexts() fills idata->fi.IndexNumber */
rc = smb2_parse_contexts(server, &rsp_iov[0], &oparms->fid->epoch,
oparms->fid->lease_key, &oplock, &idata->fi, NULL);
+ if (rc)
+ cifs_dbg(VFS, "rc: %d parsing context of compound op\n", rc);
}
for (i = 0; i < num_cmds; i++) {
- char *buf = rsp_iov[i + i].iov_base;
+ char *buf = rsp_iov[i + 1].iov_base;
if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
rc = server->ops->map_error(buf, false);
@@ -728,19 +642,6 @@ finished:
trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
ses->Suid);
break;
- case SMB2_OP_DELETE:
- if (rc)
- trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
- else {
- /*
- * If dentry (hence, inode) is NULL, lease break is going to
- * take care of degrading leases on handles for deleted files.
- */
- if (inode)
- cifs_mark_open_handles_for_deleted_file(inode, full_path);
- trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
- }
- break;
case SMB2_OP_MKDIR:
if (rc)
trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
@@ -761,11 +662,11 @@ finished:
trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
SMB2_set_info_free(&rqst[num_rqst++]);
break;
- case SMB2_OP_RMDIR:
- if (rc)
- trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
+ case SMB2_OP_UNLINK:
+ if (!rc)
+ trace_smb3_unlink_done(xid, tcon->tid, ses->Suid);
else
- trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
+ trace_smb3_unlink_err(xid, tcon->tid, ses->Suid, rc);
SMB2_set_info_free(&rqst[num_rqst++]);
break;
case SMB2_OP_SET_EOF:
@@ -862,6 +763,7 @@ finished:
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
+out:
if (cfile)
cifsFileInfo_put(cfile);
@@ -1056,10 +958,11 @@ int smb2_query_path_info(const unsigned int xid,
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
* response.
*/
- if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
+ if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK) {
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
- if (!tcon->posix_extensions)
- cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
+ if (!tcon->posix_extensions)
+ cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
+ }
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
FILE_READ_ATTRIBUTES |
@@ -1138,7 +1041,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
cifs_i = CIFS_I(inode);
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
data.Attributes = cpu_to_le32(dosattrs);
- cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
+ cifs_get_writable_path(tcon, name, inode, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
@@ -1160,7 +1063,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
return smb2_compound_op(xid, tcon, cifs_sb,
name, &oparms, NULL,
- &(int){SMB2_OP_RMDIR}, 1,
+ &(int){SMB2_OP_UNLINK}, 1,
NULL, NULL, NULL, NULL);
}
@@ -1168,21 +1071,112 @@ int
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
struct cifs_sb_info *cifs_sb, struct dentry *dentry)
{
+ struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
+ __le16 *utf16_path __free(kfree) = NULL;
+ int retries = 0, cur_sleep = 0;
+ struct TCP_Server_Info *server;
struct cifs_open_parms oparms;
+ struct smb2_create_req *creq;
+ struct inode *inode = NULL;
+ struct smb_rqst rqst[2];
+ struct kvec rsp_iov[2];
+ struct kvec close_iov;
+ int resp_buftype[2];
+ struct cifs_fid fid;
+ int flags = 0;
+ __u8 oplock;
+ int rc;
- oparms = CIFS_OPARMS(cifs_sb, tcon, name,
- DELETE, FILE_OPEN,
- CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
- ACL_NO_MODE);
- int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
- NULL, &(int){SMB2_OP_DELETE}, 1,
- NULL, NULL, NULL, dentry);
- if (rc == -EINVAL) {
- cifs_dbg(FYI, "invalid lease key, resending request without lease");
- rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
- NULL, &(int){SMB2_OP_DELETE}, 1,
- NULL, NULL, NULL, NULL);
+ utf16_path = cifs_convert_path_to_utf16(name, cifs_sb);
+ if (!utf16_path)
+ return -ENOMEM;
+
+ if (smb3_encryption_required(tcon))
+ flags |= CIFS_TRANSFORM_REQ;
+again:
+ oplock = SMB2_OPLOCK_LEVEL_NONE;
+ server = cifs_pick_channel(tcon->ses);
+
+ memset(rqst, 0, sizeof(rqst));
+ memset(resp_buftype, 0, sizeof(resp_buftype));
+ memset(rsp_iov, 0, sizeof(rsp_iov));
+
+ memset(open_iov, 0, sizeof(open_iov));
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = ARRAY_SIZE(open_iov);
+
+ oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE | FILE_READ_ATTRIBUTES,
+ FILE_OPEN, CREATE_DELETE_ON_CLOSE |
+ OPEN_REPARSE_POINT, ACL_NO_MODE);
+ oparms.fid = &fid;
+
+ if (dentry) {
+ inode = d_inode(dentry);
+ if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
+ oplock = SMB2_OPLOCK_LEVEL_LEASE;
+ server->ops->get_lease_key(inode, &fid);
+ }
+ }
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+ if (rc)
+ goto err_free;
+ smb2_set_next_command(tcon, &rqst[0]);
+ creq = rqst[0].rq_iov[0].iov_base;
+ creq->ShareAccess = FILE_SHARE_DELETE_LE;
+
+ memset(&close_iov, 0, sizeof(close_iov));
+ rqst[1].rq_iov = &close_iov;
+ rqst[1].rq_nvec = 1;
+
+ rc = SMB2_close_init(tcon, server, &rqst[1],
+ COMPOUND_FID, COMPOUND_FID, false);
+ if (rc)
+ goto err_free;
+ smb2_set_related(&rqst[1]);
+
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
+ for (int i = 0; i < ARRAY_SIZE(rqst); i++)
+ smb2_set_replay(server, &rqst[i]);
+ }
+
+ rc = compound_send_recv(xid, tcon->ses, server, flags,
+ ARRAY_SIZE(rqst), rqst,
+ resp_buftype, rsp_iov);
+ SMB2_open_free(&rqst[0]);
+ SMB2_close_free(&rqst[1]);
+ free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
+ free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
+
+ if (is_replayable_error(rc) &&
+ smb2_should_replay(tcon, &retries, &cur_sleep))
+ goto again;
+
+ /* Retry compound request without lease */
+ if (rc == -EINVAL && dentry) {
+ dentry = NULL;
+ retries = 0;
+ cur_sleep = 0;
+ goto again;
}
+ /*
+ * If dentry (hence, inode) is NULL, lease break is going to
+ * take care of degrading leases on handles for deleted files.
+ */
+ if (!rc && inode)
+ cifs_mark_open_handles_for_deleted_file(inode, name);
+
+ return rc;
+
+err_free:
+ SMB2_open_free(&rqst[0]);
+ SMB2_close_free(&rqst[1]);
+ free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
+ free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
return rc;
}
@@ -1201,6 +1195,8 @@ static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
if (smb2_to_name == NULL) {
rc = -ENOMEM;
+ if (cfile)
+ cifsFileInfo_put(cfile);
goto smb2_rename_path;
}
in_iov.iov_base = smb2_to_name;
@@ -1221,35 +1217,62 @@ int smb2_rename_path(const unsigned int xid,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
+ struct inode *inode = source_dentry ? d_inode(source_dentry) : NULL;
struct cifsFileInfo *cfile;
__u32 co = file_create_options(source_dentry);
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
- cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease");
- cifs_get_writable_path(tcon, from_name,
- FIND_WR_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, NULL);
}
return rc;
}
+static int clear_tmpfile_attr(const unsigned int xid, struct cifs_tcon *tcon,
+ struct inode *inode, const char *full_path)
+{
+ struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ FILE_BASIC_INFO fi;
+
+ cinode->cifsAttrs &= ~(ATTR_TEMPORARY | ATTR_HIDDEN);
+ fi = (FILE_BASIC_INFO) {
+ .Attributes = cpu_to_le32(cinode->cifsAttrs),
+ };
+ return server->ops->set_file_info(inode, full_path, &fi, xid);
+}
+
int smb2_create_hardlink(const unsigned int xid,
struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
+ struct inode *inode = source_dentry ? d_inode(source_dentry) : NULL;
__u32 co = file_create_options(source_dentry);
+ struct cifsFileInfo *cfile;
+ int rc;
+
+ if (inode && test_bit(CIFS_INO_TMPFILE, &CIFS_I(inode)->flags)) {
+ rc = clear_tmpfile_attr(xid, tcon, inode, from_name);
+ if (rc)
+ return rc;
+ }
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name,
cifs_sb, co, FILE_READ_ATTRIBUTES,
- SMB2_OP_HARDLINK, NULL, NULL);
+ SMB2_OP_HARDLINK, cfile, NULL);
}
int
@@ -1258,15 +1281,16 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, bool set_alloc,
struct dentry *dentry)
{
+ struct inode *inode = dentry ? d_inode(dentry) : NULL;
+ __le64 eof = cpu_to_le64(size);
struct cifs_open_parms oparms;
struct cifsFileInfo *cfile;
struct kvec in_iov;
- __le64 eof = cpu_to_le64(size);
int rc;
in_iov.iov_base = &eof;
in_iov.iov_len = sizeof(eof);
- cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, inode, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
FILE_OPEN, 0, ACL_NO_MODE);
@@ -1276,7 +1300,8 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile, NULL, NULL, dentry);
if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease");
- cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path,
+ inode, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov,
&(int){SMB2_OP_SET_EOF}, 1,
@@ -1289,36 +1314,39 @@ int
smb2_set_file_info(struct inode *inode, const char *full_path,
FILE_BASIC_INFO *buf, const unsigned int xid)
{
- struct cifs_open_parms oparms;
+ struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifsFileInfo *cfile = NULL;
+ struct cifs_open_parms oparms;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
- struct cifsFileInfo *cfile;
- struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
- int rc;
-
- if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
- (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
- (buf->Attributes == 0))
- return 0; /* would be a no op, no sense sending this */
+ int rc = 0;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
- cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
+ if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
+ (buf->LastWriteTime == 0) && (buf->ChangeTime == 0)) {
+ if (buf->Attributes == 0)
+ goto out; /* would be a no op, no sense sending this */
+ cifs_get_writable_path(tcon, full_path,
+ inode, FIND_ANY, &cfile);
+ }
+
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
FILE_OPEN, 0, ACL_NO_MODE);
rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov,
&(int){SMB2_OP_SET_INFO}, 1,
cfile, NULL, NULL, NULL);
+out:
cifs_put_tlink(tlink);
return rc;
}
-struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
+struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data,
struct super_block *sb,
const unsigned int xid,
struct cifs_tcon *tcon,
@@ -1343,7 +1371,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
* attempt to create reparse point. This will prevent creating unusable
* empty object on the server.
*/
- if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS))
+ if (!CIFS_REPARSE_SUPPORT(tcon))
return ERR_PTR(-EOPNOTSUPP);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
@@ -1363,7 +1391,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
if (tcon->posix_extensions) {
cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
- cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, NULL, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
@@ -1372,7 +1400,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
}
} else {
cmds[1] = SMB2_OP_QUERY_INFO;
- cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, NULL, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
@@ -1435,3 +1463,98 @@ out:
cifs_free_open_info(&data);
return rc;
}
+
+static inline __le16 *utf16_smb2_path(struct cifs_sb_info *cifs_sb,
+ const char *name, size_t namelen)
+{
+ int len;
+
+ if (*name == '\\' ||
+ (cifs_sb_master_tlink(cifs_sb) &&
+ cifs_sb_master_tcon(cifs_sb)->posix_extensions && *name == '/'))
+ name++;
+ return cifs_strndup_to_utf16(name, namelen, &len,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+}
+
+int smb2_rename_pending_delete(const char *full_path,
+ struct dentry *dentry,
+ const unsigned int xid)
+{
+ struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry);
+ __le16 *utf16_path __free(kfree) = NULL;
+ __u32 co = file_create_options(dentry);
+ int cmds[] = {
+ SMB2_OP_SET_INFO,
+ SMB2_OP_RENAME,
+ SMB2_OP_UNLINK,
+ };
+ const int num_cmds = ARRAY_SIZE(cmds);
+ char *to_name __free(kfree) = NULL;
+ __u32 attrs = cinode->cifsAttrs;
+ struct cifs_open_parms oparms;
+ struct cifsFileInfo *cfile;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct kvec iov[2];
+ int rc;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ to_name = cifs_silly_fullpath(dentry);
+ if (IS_ERR(to_name)) {
+ rc = PTR_ERR(to_name);
+ to_name = NULL;
+ goto out;
+ }
+
+ utf16_path = utf16_smb2_path(cifs_sb, to_name, strlen(to_name));
+ if (!utf16_path) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ drop_cached_dir_by_name(xid, tcon, full_path, cifs_sb);
+ oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
+ DELETE | FILE_WRITE_ATTRIBUTES,
+ FILE_OPEN, co, ACL_NO_MODE);
+
+ attrs &= ~ATTR_READONLY;
+ if (!attrs)
+ attrs = ATTR_NORMAL;
+ if (d_inode(dentry)->i_nlink <= 1)
+ attrs |= ATTR_HIDDEN;
+ iov[0].iov_base = &(FILE_BASIC_INFO) {
+ .Attributes = cpu_to_le32(attrs),
+ };
+ iov[0].iov_len = sizeof(FILE_BASIC_INFO);
+ iov[1].iov_base = utf16_path;
+ iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path);
+
+ cifs_get_writable_path(tcon, full_path, d_inode(dentry),
+ FIND_WITH_DELETE, &cfile);
+ rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
+ cmds, num_cmds, cfile, NULL, NULL, dentry);
+ if (rc == -EINVAL) {
+ cifs_dbg(FYI, "invalid lease key, resending request without lease\n");
+ cifs_get_writable_path(tcon, full_path, d_inode(dentry),
+ FIND_WITH_DELETE, &cfile);
+ rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
+ cmds, num_cmds, cfile, NULL, NULL, NULL);
+ }
+ if (!rc) {
+ set_bit(CIFS_INO_DELETE_PENDING, &cinode->flags);
+ } else {
+ cifs_tcon_dbg(FYI, "%s: failed to rename '%s' to '%s': %d\n",
+ __func__, full_path, to_name, rc);
+ rc = smb_EIO1(smb_eio_trace_pend_del_fail, rc);
+ }
+out:
+ cifs_put_tlink(tlink);
+ return rc;
+}
diff --git a/fs/smb/client/smb2maperror.c b/fs/smb/client/smb2maperror.c
index 12c2b868789f..9ed21f7b618c 100644
--- a/fs/smb/client/smb2maperror.c
+++ b/fs/smb/client/smb2maperror.c
@@ -8,2441 +8,51 @@
*
*/
#include <linux/errno.h>
-#include "cifsglob.h"
+#include "cifsproto.h"
#include "cifs_debug.h"
-#include "smb2pdu.h"
#include "smb2proto.h"
-#include "../common/smb2status.h"
#include "smb2glob.h"
+#include "../common/smb2status.h"
#include "trace.h"
-struct status_to_posix_error {
- __le32 smb2_status;
- int posix_error;
- char *status_string;
-};
-
static const struct status_to_posix_error smb2_error_map_table[] = {
- {STATUS_SUCCESS, 0, "STATUS_SUCCESS"},
- {STATUS_WAIT_0, 0, "STATUS_WAIT_0"},
- {STATUS_WAIT_1, -EIO, "STATUS_WAIT_1"},
- {STATUS_WAIT_2, -EIO, "STATUS_WAIT_2"},
- {STATUS_WAIT_3, -EIO, "STATUS_WAIT_3"},
- {STATUS_WAIT_63, -EIO, "STATUS_WAIT_63"},
- {STATUS_ABANDONED, -EIO, "STATUS_ABANDONED"},
- {STATUS_ABANDONED_WAIT_0, -EIO, "STATUS_ABANDONED_WAIT_0"},
- {STATUS_ABANDONED_WAIT_63, -EIO, "STATUS_ABANDONED_WAIT_63"},
- {STATUS_USER_APC, -EIO, "STATUS_USER_APC"},
- {STATUS_KERNEL_APC, -EIO, "STATUS_KERNEL_APC"},
- {STATUS_ALERTED, -EIO, "STATUS_ALERTED"},
- {STATUS_TIMEOUT, -ETIMEDOUT, "STATUS_TIMEOUT"},
- {STATUS_PENDING, -EIO, "STATUS_PENDING"},
- {STATUS_REPARSE, -EIO, "STATUS_REPARSE"},
- {STATUS_MORE_ENTRIES, -EIO, "STATUS_MORE_ENTRIES"},
- {STATUS_NOT_ALL_ASSIGNED, -EIO, "STATUS_NOT_ALL_ASSIGNED"},
- {STATUS_SOME_NOT_MAPPED, -EIO, "STATUS_SOME_NOT_MAPPED"},
- {STATUS_OPLOCK_BREAK_IN_PROGRESS, -EIO,
- "STATUS_OPLOCK_BREAK_IN_PROGRESS"},
- {STATUS_VOLUME_MOUNTED, -EIO, "STATUS_VOLUME_MOUNTED"},
- {STATUS_RXACT_COMMITTED, -EIO, "STATUS_RXACT_COMMITTED"},
- {STATUS_NOTIFY_CLEANUP, -EIO, "STATUS_NOTIFY_CLEANUP"},
- {STATUS_NOTIFY_ENUM_DIR, -EIO, "STATUS_NOTIFY_ENUM_DIR"},
- {STATUS_NO_QUOTAS_FOR_ACCOUNT, -EIO, "STATUS_NO_QUOTAS_FOR_ACCOUNT"},
- {STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED, -EIO,
- "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"},
- {STATUS_PAGE_FAULT_TRANSITION, -EIO, "STATUS_PAGE_FAULT_TRANSITION"},
- {STATUS_PAGE_FAULT_DEMAND_ZERO, -EIO, "STATUS_PAGE_FAULT_DEMAND_ZERO"},
- {STATUS_PAGE_FAULT_COPY_ON_WRITE, -EIO,
- "STATUS_PAGE_FAULT_COPY_ON_WRITE"},
- {STATUS_PAGE_FAULT_GUARD_PAGE, -EIO, "STATUS_PAGE_FAULT_GUARD_PAGE"},
- {STATUS_PAGE_FAULT_PAGING_FILE, -EIO, "STATUS_PAGE_FAULT_PAGING_FILE"},
- {STATUS_CACHE_PAGE_LOCKED, -EIO, "STATUS_CACHE_PAGE_LOCKED"},
- {STATUS_CRASH_DUMP, -EIO, "STATUS_CRASH_DUMP"},
- {STATUS_BUFFER_ALL_ZEROS, -EIO, "STATUS_BUFFER_ALL_ZEROS"},
- {STATUS_REPARSE_OBJECT, -EIO, "STATUS_REPARSE_OBJECT"},
- {STATUS_RESOURCE_REQUIREMENTS_CHANGED, -EIO,
- "STATUS_RESOURCE_REQUIREMENTS_CHANGED"},
- {STATUS_TRANSLATION_COMPLETE, -EIO, "STATUS_TRANSLATION_COMPLETE"},
- {STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY, -EIO,
- "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"},
- {STATUS_NOTHING_TO_TERMINATE, -EIO, "STATUS_NOTHING_TO_TERMINATE"},
- {STATUS_PROCESS_NOT_IN_JOB, -EIO, "STATUS_PROCESS_NOT_IN_JOB"},
- {STATUS_PROCESS_IN_JOB, -EIO, "STATUS_PROCESS_IN_JOB"},
- {STATUS_VOLSNAP_HIBERNATE_READY, -EIO,
- "STATUS_VOLSNAP_HIBERNATE_READY"},
- {STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY, -EIO,
- "STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY"},
- {STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED, -EIO,
- "STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED"},
- {STATUS_INTERRUPT_STILL_CONNECTED, -EIO,
- "STATUS_INTERRUPT_STILL_CONNECTED"},
- {STATUS_PROCESS_CLONED, -EIO, "STATUS_PROCESS_CLONED"},
- {STATUS_FILE_LOCKED_WITH_ONLY_READERS, -EIO,
- "STATUS_FILE_LOCKED_WITH_ONLY_READERS"},
- {STATUS_FILE_LOCKED_WITH_WRITERS, -EIO,
- "STATUS_FILE_LOCKED_WITH_WRITERS"},
- {STATUS_RESOURCEMANAGER_READ_ONLY, -EROFS,
- "STATUS_RESOURCEMANAGER_READ_ONLY"},
- {STATUS_WAIT_FOR_OPLOCK, -EIO, "STATUS_WAIT_FOR_OPLOCK"},
- {DBG_EXCEPTION_HANDLED, -EIO, "DBG_EXCEPTION_HANDLED"},
- {DBG_CONTINUE, -EIO, "DBG_CONTINUE"},
- {STATUS_FLT_IO_COMPLETE, -EIO, "STATUS_FLT_IO_COMPLETE"},
- {STATUS_OBJECT_NAME_EXISTS, -EIO, "STATUS_OBJECT_NAME_EXISTS"},
- {STATUS_THREAD_WAS_SUSPENDED, -EIO, "STATUS_THREAD_WAS_SUSPENDED"},
- {STATUS_WORKING_SET_LIMIT_RANGE, -EIO,
- "STATUS_WORKING_SET_LIMIT_RANGE"},
- {STATUS_IMAGE_NOT_AT_BASE, -EIO, "STATUS_IMAGE_NOT_AT_BASE"},
- {STATUS_RXACT_STATE_CREATED, -EIO, "STATUS_RXACT_STATE_CREATED"},
- {STATUS_SEGMENT_NOTIFICATION, -EIO, "STATUS_SEGMENT_NOTIFICATION"},
- {STATUS_LOCAL_USER_SESSION_KEY, -EIO, "STATUS_LOCAL_USER_SESSION_KEY"},
- {STATUS_BAD_CURRENT_DIRECTORY, -EIO, "STATUS_BAD_CURRENT_DIRECTORY"},
- {STATUS_SERIAL_MORE_WRITES, -EIO, "STATUS_SERIAL_MORE_WRITES"},
- {STATUS_REGISTRY_RECOVERED, -EIO, "STATUS_REGISTRY_RECOVERED"},
- {STATUS_FT_READ_RECOVERY_FROM_BACKUP, -EIO,
- "STATUS_FT_READ_RECOVERY_FROM_BACKUP"},
- {STATUS_FT_WRITE_RECOVERY, -EIO, "STATUS_FT_WRITE_RECOVERY"},
- {STATUS_SERIAL_COUNTER_TIMEOUT, -ETIMEDOUT,
- "STATUS_SERIAL_COUNTER_TIMEOUT"},
- {STATUS_NULL_LM_PASSWORD, -EIO, "STATUS_NULL_LM_PASSWORD"},
- {STATUS_IMAGE_MACHINE_TYPE_MISMATCH, -EIO,
- "STATUS_IMAGE_MACHINE_TYPE_MISMATCH"},
- {STATUS_RECEIVE_PARTIAL, -EIO, "STATUS_RECEIVE_PARTIAL"},
- {STATUS_RECEIVE_EXPEDITED, -EIO, "STATUS_RECEIVE_EXPEDITED"},
- {STATUS_RECEIVE_PARTIAL_EXPEDITED, -EIO,
- "STATUS_RECEIVE_PARTIAL_EXPEDITED"},
- {STATUS_EVENT_DONE, -EIO, "STATUS_EVENT_DONE"},
- {STATUS_EVENT_PENDING, -EIO, "STATUS_EVENT_PENDING"},
- {STATUS_CHECKING_FILE_SYSTEM, -EIO, "STATUS_CHECKING_FILE_SYSTEM"},
- {STATUS_FATAL_APP_EXIT, -EIO, "STATUS_FATAL_APP_EXIT"},
- {STATUS_PREDEFINED_HANDLE, -EIO, "STATUS_PREDEFINED_HANDLE"},
- {STATUS_WAS_UNLOCKED, -EIO, "STATUS_WAS_UNLOCKED"},
- {STATUS_SERVICE_NOTIFICATION, -EIO, "STATUS_SERVICE_NOTIFICATION"},
- {STATUS_WAS_LOCKED, -EIO, "STATUS_WAS_LOCKED"},
- {STATUS_LOG_HARD_ERROR, -EIO, "STATUS_LOG_HARD_ERROR"},
- {STATUS_ALREADY_WIN32, -EIO, "STATUS_ALREADY_WIN32"},
- {STATUS_WX86_UNSIMULATE, -EIO, "STATUS_WX86_UNSIMULATE"},
- {STATUS_WX86_CONTINUE, -EIO, "STATUS_WX86_CONTINUE"},
- {STATUS_WX86_SINGLE_STEP, -EIO, "STATUS_WX86_SINGLE_STEP"},
- {STATUS_WX86_BREAKPOINT, -EIO, "STATUS_WX86_BREAKPOINT"},
- {STATUS_WX86_EXCEPTION_CONTINUE, -EIO,
- "STATUS_WX86_EXCEPTION_CONTINUE"},
- {STATUS_WX86_EXCEPTION_LASTCHANCE, -EIO,
- "STATUS_WX86_EXCEPTION_LASTCHANCE"},
- {STATUS_WX86_EXCEPTION_CHAIN, -EIO, "STATUS_WX86_EXCEPTION_CHAIN"},
- {STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, -EIO,
- "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"},
- {STATUS_NO_YIELD_PERFORMED, -EIO, "STATUS_NO_YIELD_PERFORMED"},
- {STATUS_TIMER_RESUME_IGNORED, -EIO, "STATUS_TIMER_RESUME_IGNORED"},
- {STATUS_ARBITRATION_UNHANDLED, -EIO, "STATUS_ARBITRATION_UNHANDLED"},
- {STATUS_CARDBUS_NOT_SUPPORTED, -ENOSYS, "STATUS_CARDBUS_NOT_SUPPORTED"},
- {STATUS_WX86_CREATEWX86TIB, -EIO, "STATUS_WX86_CREATEWX86TIB"},
- {STATUS_MP_PROCESSOR_MISMATCH, -EIO, "STATUS_MP_PROCESSOR_MISMATCH"},
- {STATUS_HIBERNATED, -EIO, "STATUS_HIBERNATED"},
- {STATUS_RESUME_HIBERNATION, -EIO, "STATUS_RESUME_HIBERNATION"},
- {STATUS_FIRMWARE_UPDATED, -EIO, "STATUS_FIRMWARE_UPDATED"},
- {STATUS_DRIVERS_LEAKING_LOCKED_PAGES, -EIO,
- "STATUS_DRIVERS_LEAKING_LOCKED_PAGES"},
- {STATUS_MESSAGE_RETRIEVED, -EIO, "STATUS_MESSAGE_RETRIEVED"},
- {STATUS_SYSTEM_POWERSTATE_TRANSITION, -EIO,
- "STATUS_SYSTEM_POWERSTATE_TRANSITION"},
- {STATUS_ALPC_CHECK_COMPLETION_LIST, -EIO,
- "STATUS_ALPC_CHECK_COMPLETION_LIST"},
- {STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, -EIO,
- "STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"},
- {STATUS_ACCESS_AUDIT_BY_POLICY, -EIO, "STATUS_ACCESS_AUDIT_BY_POLICY"},
- {STATUS_ABANDON_HIBERFILE, -EIO, "STATUS_ABANDON_HIBERFILE"},
- {STATUS_BIZRULES_NOT_ENABLED, -EIO, "STATUS_BIZRULES_NOT_ENABLED"},
- {STATUS_WAKE_SYSTEM, -EIO, "STATUS_WAKE_SYSTEM"},
- {STATUS_DS_SHUTTING_DOWN, -EIO, "STATUS_DS_SHUTTING_DOWN"},
- {DBG_REPLY_LATER, -EIO, "DBG_REPLY_LATER"},
- {DBG_UNABLE_TO_PROVIDE_HANDLE, -EIO, "DBG_UNABLE_TO_PROVIDE_HANDLE"},
- {DBG_TERMINATE_THREAD, -EIO, "DBG_TERMINATE_THREAD"},
- {DBG_TERMINATE_PROCESS, -EIO, "DBG_TERMINATE_PROCESS"},
- {DBG_CONTROL_C, -EIO, "DBG_CONTROL_C"},
- {DBG_PRINTEXCEPTION_C, -EIO, "DBG_PRINTEXCEPTION_C"},
- {DBG_RIPEXCEPTION, -EIO, "DBG_RIPEXCEPTION"},
- {DBG_CONTROL_BREAK, -EIO, "DBG_CONTROL_BREAK"},
- {DBG_COMMAND_EXCEPTION, -EIO, "DBG_COMMAND_EXCEPTION"},
- {RPC_NT_UUID_LOCAL_ONLY, -EIO, "RPC_NT_UUID_LOCAL_ONLY"},
- {RPC_NT_SEND_INCOMPLETE, -EIO, "RPC_NT_SEND_INCOMPLETE"},
- {STATUS_CTX_CDM_CONNECT, -EIO, "STATUS_CTX_CDM_CONNECT"},
- {STATUS_CTX_CDM_DISCONNECT, -EIO, "STATUS_CTX_CDM_DISCONNECT"},
- {STATUS_SXS_RELEASE_ACTIVATION_CONTEXT, -EIO,
- "STATUS_SXS_RELEASE_ACTIVATION_CONTEXT"},
- {STATUS_RECOVERY_NOT_NEEDED, -EIO, "STATUS_RECOVERY_NOT_NEEDED"},
- {STATUS_RM_ALREADY_STARTED, -EIO, "STATUS_RM_ALREADY_STARTED"},
- {STATUS_LOG_NO_RESTART, -EIO, "STATUS_LOG_NO_RESTART"},
- {STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST, -EIO,
- "STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST"},
- {STATUS_GRAPHICS_PARTIAL_DATA_POPULATED, -EIO,
- "STATUS_GRAPHICS_PARTIAL_DATA_POPULATED"},
- {STATUS_GRAPHICS_DRIVER_MISMATCH, -EIO,
- "STATUS_GRAPHICS_DRIVER_MISMATCH"},
- {STATUS_GRAPHICS_MODE_NOT_PINNED, -EIO,
- "STATUS_GRAPHICS_MODE_NOT_PINNED"},
- {STATUS_GRAPHICS_NO_PREFERRED_MODE, -EIO,
- "STATUS_GRAPHICS_NO_PREFERRED_MODE"},
- {STATUS_GRAPHICS_DATASET_IS_EMPTY, -EIO,
- "STATUS_GRAPHICS_DATASET_IS_EMPTY"},
- {STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET, -EIO,
- "STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"},
- {STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED, -EIO,
- "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"},
- {STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS, -EIO,
- "STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"},
- {STATUS_GRAPHICS_LEADLINK_START_DEFERRED, -EIO,
- "STATUS_GRAPHICS_LEADLINK_START_DEFERRED"},
- {STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY, -EIO,
- "STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY"},
- {STATUS_GRAPHICS_START_DEFERRED, -EIO,
- "STATUS_GRAPHICS_START_DEFERRED"},
- {STATUS_NDIS_INDICATION_REQUIRED, -EIO,
- "STATUS_NDIS_INDICATION_REQUIRED"},
- {STATUS_GUARD_PAGE_VIOLATION, -EIO, "STATUS_GUARD_PAGE_VIOLATION"},
- {STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
- {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
- {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
- {STATUS_BUFFER_OVERFLOW, -E2BIG, "STATUS_BUFFER_OVERFLOW"},
- {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
- {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
- {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
- {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
- {STATUS_GUID_SUBSTITUTION_MADE, -EIO, "STATUS_GUID_SUBSTITUTION_MADE"},
- {STATUS_PARTIAL_COPY, -EIO, "STATUS_PARTIAL_COPY"},
- {STATUS_DEVICE_PAPER_EMPTY, -EIO, "STATUS_DEVICE_PAPER_EMPTY"},
- {STATUS_DEVICE_POWERED_OFF, -EIO, "STATUS_DEVICE_POWERED_OFF"},
- {STATUS_DEVICE_OFF_LINE, -EIO, "STATUS_DEVICE_OFF_LINE"},
- {STATUS_DEVICE_BUSY, -EBUSY, "STATUS_DEVICE_BUSY"},
- {STATUS_NO_MORE_EAS, -EIO, "STATUS_NO_MORE_EAS"},
- {STATUS_INVALID_EA_NAME, -EINVAL, "STATUS_INVALID_EA_NAME"},
- {STATUS_EA_LIST_INCONSISTENT, -EIO, "STATUS_EA_LIST_INCONSISTENT"},
- {STATUS_INVALID_EA_FLAG, -EINVAL, "STATUS_INVALID_EA_FLAG"},
- {STATUS_VERIFY_REQUIRED, -EIO, "STATUS_VERIFY_REQUIRED"},
- {STATUS_EXTRANEOUS_INFORMATION, -EIO, "STATUS_EXTRANEOUS_INFORMATION"},
- {STATUS_RXACT_COMMIT_NECESSARY, -EIO, "STATUS_RXACT_COMMIT_NECESSARY"},
- {STATUS_NO_MORE_ENTRIES, -EIO, "STATUS_NO_MORE_ENTRIES"},
- {STATUS_FILEMARK_DETECTED, -EIO, "STATUS_FILEMARK_DETECTED"},
- {STATUS_MEDIA_CHANGED, -EIO, "STATUS_MEDIA_CHANGED"},
- {STATUS_BUS_RESET, -EIO, "STATUS_BUS_RESET"},
- {STATUS_END_OF_MEDIA, -EIO, "STATUS_END_OF_MEDIA"},
- {STATUS_BEGINNING_OF_MEDIA, -EIO, "STATUS_BEGINNING_OF_MEDIA"},
- {STATUS_MEDIA_CHECK, -EIO, "STATUS_MEDIA_CHECK"},
- {STATUS_SETMARK_DETECTED, -EIO, "STATUS_SETMARK_DETECTED"},
- {STATUS_NO_DATA_DETECTED, -EIO, "STATUS_NO_DATA_DETECTED"},
- {STATUS_REDIRECTOR_HAS_OPEN_HANDLES, -EIO,
- "STATUS_REDIRECTOR_HAS_OPEN_HANDLES"},
- {STATUS_SERVER_HAS_OPEN_HANDLES, -EIO,
- "STATUS_SERVER_HAS_OPEN_HANDLES"},
- {STATUS_ALREADY_DISCONNECTED, -EIO, "STATUS_ALREADY_DISCONNECTED"},
- {STATUS_LONGJUMP, -EIO, "STATUS_LONGJUMP"},
- {STATUS_CLEANER_CARTRIDGE_INSTALLED, -EIO,
- "STATUS_CLEANER_CARTRIDGE_INSTALLED"},
- {STATUS_PLUGPLAY_QUERY_VETOED, -EIO, "STATUS_PLUGPLAY_QUERY_VETOED"},
- {STATUS_UNWIND_CONSOLIDATE, -EIO, "STATUS_UNWIND_CONSOLIDATE"},
- {STATUS_REGISTRY_HIVE_RECOVERED, -EIO,
- "STATUS_REGISTRY_HIVE_RECOVERED"},
- {STATUS_DLL_MIGHT_BE_INSECURE, -EIO, "STATUS_DLL_MIGHT_BE_INSECURE"},
- {STATUS_DLL_MIGHT_BE_INCOMPATIBLE, -EIO,
- "STATUS_DLL_MIGHT_BE_INCOMPATIBLE"},
- {STATUS_STOPPED_ON_SYMLINK, -EOPNOTSUPP, "STATUS_STOPPED_ON_SYMLINK"},
- {STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EOPNOTSUPP,
- "STATUS_REPARSE_NOT_HANDLED"},
- {STATUS_DEVICE_REQUIRES_CLEANING, -EIO,
- "STATUS_DEVICE_REQUIRES_CLEANING"},
- {STATUS_DEVICE_DOOR_OPEN, -EIO, "STATUS_DEVICE_DOOR_OPEN"},
- {STATUS_DATA_LOST_REPAIR, -EIO, "STATUS_DATA_LOST_REPAIR"},
- {DBG_EXCEPTION_NOT_HANDLED, -EIO, "DBG_EXCEPTION_NOT_HANDLED"},
- {STATUS_CLUSTER_NODE_ALREADY_UP, -EIO,
- "STATUS_CLUSTER_NODE_ALREADY_UP"},
- {STATUS_CLUSTER_NODE_ALREADY_DOWN, -EIO,
- "STATUS_CLUSTER_NODE_ALREADY_DOWN"},
- {STATUS_CLUSTER_NETWORK_ALREADY_ONLINE, -EIO,
- "STATUS_CLUSTER_NETWORK_ALREADY_ONLINE"},
- {STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE, -EIO,
- "STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE"},
- {STATUS_CLUSTER_NODE_ALREADY_MEMBER, -EIO,
- "STATUS_CLUSTER_NODE_ALREADY_MEMBER"},
- {STATUS_COULD_NOT_RESIZE_LOG, -EIO, "STATUS_COULD_NOT_RESIZE_LOG"},
- {STATUS_NO_TXF_METADATA, -EIO, "STATUS_NO_TXF_METADATA"},
- {STATUS_CANT_RECOVER_WITH_HANDLE_OPEN, -EIO,
- "STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"},
- {STATUS_TXF_METADATA_ALREADY_PRESENT, -EIO,
- "STATUS_TXF_METADATA_ALREADY_PRESENT"},
- {STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, -EIO,
- "STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"},
- {STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED, -EIO,
- "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED"},
- {STATUS_FLT_BUFFER_TOO_SMALL, -ENOBUFS, "STATUS_FLT_BUFFER_TOO_SMALL"},
- {STATUS_FVE_PARTIAL_METADATA, -EIO, "STATUS_FVE_PARTIAL_METADATA"},
- {STATUS_UNSUCCESSFUL, -EIO, "STATUS_UNSUCCESSFUL"},
- {STATUS_NOT_IMPLEMENTED, -EOPNOTSUPP, "STATUS_NOT_IMPLEMENTED"},
- {STATUS_INVALID_INFO_CLASS, -EIO, "STATUS_INVALID_INFO_CLASS"},
- {STATUS_INFO_LENGTH_MISMATCH, -EIO, "STATUS_INFO_LENGTH_MISMATCH"},
- {STATUS_ACCESS_VIOLATION, -EACCES, "STATUS_ACCESS_VIOLATION"},
- {STATUS_IN_PAGE_ERROR, -EFAULT, "STATUS_IN_PAGE_ERROR"},
- {STATUS_PAGEFILE_QUOTA, -EDQUOT, "STATUS_PAGEFILE_QUOTA"},
- {STATUS_INVALID_HANDLE, -EBADF, "STATUS_INVALID_HANDLE"},
- {STATUS_BAD_INITIAL_STACK, -EIO, "STATUS_BAD_INITIAL_STACK"},
- {STATUS_BAD_INITIAL_PC, -EIO, "STATUS_BAD_INITIAL_PC"},
- {STATUS_INVALID_CID, -EIO, "STATUS_INVALID_CID"},
- {STATUS_TIMER_NOT_CANCELED, -EIO, "STATUS_TIMER_NOT_CANCELED"},
- {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"},
- {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"},
- {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"},
- {STATUS_INVALID_DEVICE_REQUEST, -EOPNOTSUPP, "STATUS_INVALID_DEVICE_REQUEST"},
- {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"},
- {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"},
- {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"},
- {STATUS_UNRECOGNIZED_MEDIA, -EIO, "STATUS_UNRECOGNIZED_MEDIA"},
- {STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"},
- {STATUS_MORE_PROCESSING_REQUIRED, -EIO,
- "STATUS_MORE_PROCESSING_REQUIRED"},
- {STATUS_NO_MEMORY, -EREMOTEIO, "STATUS_NO_MEMORY"},
- {STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE,
- "STATUS_CONFLICTING_ADDRESSES"},
- {STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"},
- {STATUS_UNABLE_TO_FREE_VM, -EIO, "STATUS_UNABLE_TO_FREE_VM"},
- {STATUS_UNABLE_TO_DELETE_SECTION, -EIO,
- "STATUS_UNABLE_TO_DELETE_SECTION"},
- {STATUS_INVALID_SYSTEM_SERVICE, -EIO, "STATUS_INVALID_SYSTEM_SERVICE"},
- {STATUS_ILLEGAL_INSTRUCTION, -EIO, "STATUS_ILLEGAL_INSTRUCTION"},
- {STATUS_INVALID_LOCK_SEQUENCE, -EIO, "STATUS_INVALID_LOCK_SEQUENCE"},
- {STATUS_INVALID_VIEW_SIZE, -EIO, "STATUS_INVALID_VIEW_SIZE"},
- {STATUS_INVALID_FILE_FOR_SECTION, -EIO,
- "STATUS_INVALID_FILE_FOR_SECTION"},
- {STATUS_ALREADY_COMMITTED, -EIO, "STATUS_ALREADY_COMMITTED"},
- {STATUS_ACCESS_DENIED, -EACCES, "STATUS_ACCESS_DENIED"},
- {STATUS_BUFFER_TOO_SMALL, -EIO, "STATUS_BUFFER_TOO_SMALL"},
- {STATUS_OBJECT_TYPE_MISMATCH, -EIO, "STATUS_OBJECT_TYPE_MISMATCH"},
- {STATUS_NONCONTINUABLE_EXCEPTION, -EIO,
- "STATUS_NONCONTINUABLE_EXCEPTION"},
- {STATUS_INVALID_DISPOSITION, -EIO, "STATUS_INVALID_DISPOSITION"},
- {STATUS_UNWIND, -EIO, "STATUS_UNWIND"},
- {STATUS_BAD_STACK, -EIO, "STATUS_BAD_STACK"},
- {STATUS_INVALID_UNWIND_TARGET, -EIO, "STATUS_INVALID_UNWIND_TARGET"},
- {STATUS_NOT_LOCKED, -EIO, "STATUS_NOT_LOCKED"},
- {STATUS_PARITY_ERROR, -EIO, "STATUS_PARITY_ERROR"},
- {STATUS_UNABLE_TO_DECOMMIT_VM, -EIO, "STATUS_UNABLE_TO_DECOMMIT_VM"},
- {STATUS_NOT_COMMITTED, -EIO, "STATUS_NOT_COMMITTED"},
- {STATUS_INVALID_PORT_ATTRIBUTES, -EIO,
- "STATUS_INVALID_PORT_ATTRIBUTES"},
- {STATUS_PORT_MESSAGE_TOO_LONG, -EIO, "STATUS_PORT_MESSAGE_TOO_LONG"},
- {STATUS_INVALID_PARAMETER_MIX, -EINVAL, "STATUS_INVALID_PARAMETER_MIX"},
- {STATUS_INVALID_QUOTA_LOWER, -EIO, "STATUS_INVALID_QUOTA_LOWER"},
- {STATUS_DISK_CORRUPT_ERROR, -EIO, "STATUS_DISK_CORRUPT_ERROR"},
- {STATUS_OBJECT_NAME_INVALID, -ENOENT, "STATUS_OBJECT_NAME_INVALID"},
- {STATUS_OBJECT_NAME_NOT_FOUND, -ENOENT, "STATUS_OBJECT_NAME_NOT_FOUND"},
- {STATUS_OBJECT_NAME_COLLISION, -EEXIST, "STATUS_OBJECT_NAME_COLLISION"},
- {STATUS_PORT_DISCONNECTED, -EIO, "STATUS_PORT_DISCONNECTED"},
- {STATUS_DEVICE_ALREADY_ATTACHED, -EIO,
- "STATUS_DEVICE_ALREADY_ATTACHED"},
- {STATUS_OBJECT_PATH_INVALID, -ENOTDIR, "STATUS_OBJECT_PATH_INVALID"},
- {STATUS_OBJECT_PATH_NOT_FOUND, -ENOENT, "STATUS_OBJECT_PATH_NOT_FOUND"},
- {STATUS_OBJECT_PATH_SYNTAX_BAD, -EIO, "STATUS_OBJECT_PATH_SYNTAX_BAD"},
- {STATUS_DATA_OVERRUN, -EIO, "STATUS_DATA_OVERRUN"},
- {STATUS_DATA_LATE_ERROR, -EIO, "STATUS_DATA_LATE_ERROR"},
- {STATUS_DATA_ERROR, -EIO, "STATUS_DATA_ERROR"},
- {STATUS_CRC_ERROR, -EIO, "STATUS_CRC_ERROR"},
- {STATUS_SECTION_TOO_BIG, -EIO, "STATUS_SECTION_TOO_BIG"},
- {STATUS_PORT_CONNECTION_REFUSED, -ECONNREFUSED,
- "STATUS_PORT_CONNECTION_REFUSED"},
- {STATUS_INVALID_PORT_HANDLE, -EIO, "STATUS_INVALID_PORT_HANDLE"},
- {STATUS_SHARING_VIOLATION, -EBUSY, "STATUS_SHARING_VIOLATION"},
- {STATUS_QUOTA_EXCEEDED, -EDQUOT, "STATUS_QUOTA_EXCEEDED"},
- {STATUS_INVALID_PAGE_PROTECTION, -EIO,
- "STATUS_INVALID_PAGE_PROTECTION"},
- {STATUS_MUTANT_NOT_OWNED, -EIO, "STATUS_MUTANT_NOT_OWNED"},
- {STATUS_SEMAPHORE_LIMIT_EXCEEDED, -EIO,
- "STATUS_SEMAPHORE_LIMIT_EXCEEDED"},
- {STATUS_PORT_ALREADY_SET, -EIO, "STATUS_PORT_ALREADY_SET"},
- {STATUS_SECTION_NOT_IMAGE, -EIO, "STATUS_SECTION_NOT_IMAGE"},
- {STATUS_SUSPEND_COUNT_EXCEEDED, -EIO, "STATUS_SUSPEND_COUNT_EXCEEDED"},
- {STATUS_THREAD_IS_TERMINATING, -EIO, "STATUS_THREAD_IS_TERMINATING"},
- {STATUS_BAD_WORKING_SET_LIMIT, -EIO, "STATUS_BAD_WORKING_SET_LIMIT"},
- {STATUS_INCOMPATIBLE_FILE_MAP, -EIO, "STATUS_INCOMPATIBLE_FILE_MAP"},
- {STATUS_SECTION_PROTECTION, -EIO, "STATUS_SECTION_PROTECTION"},
- {STATUS_EAS_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_EAS_NOT_SUPPORTED"},
- {STATUS_EA_TOO_LARGE, -EIO, "STATUS_EA_TOO_LARGE"},
- {STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"},
- {STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
- {STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
- {STATUS_FILE_LOCK_CONFLICT, -EACCES, "STATUS_FILE_LOCK_CONFLICT"},
- {STATUS_LOCK_NOT_GRANTED, -EACCES, "STATUS_LOCK_NOT_GRANTED"},
- {STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
- {STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
- "STATUS_CTL_FILE_NOT_SUPPORTED"},
- {STATUS_UNKNOWN_REVISION, -EIO, "STATUS_UNKNOWN_REVISION"},
- {STATUS_REVISION_MISMATCH, -EIO, "STATUS_REVISION_MISMATCH"},
- {STATUS_INVALID_OWNER, -EIO, "STATUS_INVALID_OWNER"},
- {STATUS_INVALID_PRIMARY_GROUP, -EIO, "STATUS_INVALID_PRIMARY_GROUP"},
- {STATUS_NO_IMPERSONATION_TOKEN, -EIO, "STATUS_NO_IMPERSONATION_TOKEN"},
- {STATUS_CANT_DISABLE_MANDATORY, -EIO, "STATUS_CANT_DISABLE_MANDATORY"},
- {STATUS_NO_LOGON_SERVERS, -EIO, "STATUS_NO_LOGON_SERVERS"},
- {STATUS_NO_SUCH_LOGON_SESSION, -EIO, "STATUS_NO_SUCH_LOGON_SESSION"},
- {STATUS_NO_SUCH_PRIVILEGE, -EIO, "STATUS_NO_SUCH_PRIVILEGE"},
- {STATUS_PRIVILEGE_NOT_HELD, -EPERM, "STATUS_PRIVILEGE_NOT_HELD"},
- {STATUS_INVALID_ACCOUNT_NAME, -EIO, "STATUS_INVALID_ACCOUNT_NAME"},
- {STATUS_USER_EXISTS, -EIO, "STATUS_USER_EXISTS"},
- {STATUS_NO_SUCH_USER, -EIO, "STATUS_NO_SUCH_USER"},
- {STATUS_GROUP_EXISTS, -EIO, "STATUS_GROUP_EXISTS"},
- {STATUS_NO_SUCH_GROUP, -EIO, "STATUS_NO_SUCH_GROUP"},
- {STATUS_MEMBER_IN_GROUP, -EIO, "STATUS_MEMBER_IN_GROUP"},
- {STATUS_MEMBER_NOT_IN_GROUP, -EIO, "STATUS_MEMBER_NOT_IN_GROUP"},
- {STATUS_LAST_ADMIN, -EIO, "STATUS_LAST_ADMIN"},
- {STATUS_WRONG_PASSWORD, -EACCES, "STATUS_WRONG_PASSWORD"},
- {STATUS_ILL_FORMED_PASSWORD, -EINVAL, "STATUS_ILL_FORMED_PASSWORD"},
- {STATUS_PASSWORD_RESTRICTION, -EACCES, "STATUS_PASSWORD_RESTRICTION"},
- {STATUS_LOGON_FAILURE, -EACCES, "STATUS_LOGON_FAILURE"},
- {STATUS_ACCOUNT_RESTRICTION, -EACCES, "STATUS_ACCOUNT_RESTRICTION"},
- {STATUS_INVALID_LOGON_HOURS, -EACCES, "STATUS_INVALID_LOGON_HOURS"},
- {STATUS_INVALID_WORKSTATION, -EACCES, "STATUS_INVALID_WORKSTATION"},
- {STATUS_PASSWORD_EXPIRED, -EKEYEXPIRED, "STATUS_PASSWORD_EXPIRED"},
- {STATUS_ACCOUNT_DISABLED, -EKEYREVOKED, "STATUS_ACCOUNT_DISABLED"},
- {STATUS_NONE_MAPPED, -EIO, "STATUS_NONE_MAPPED"},
- {STATUS_TOO_MANY_LUIDS_REQUESTED, -EIO,
- "STATUS_TOO_MANY_LUIDS_REQUESTED"},
- {STATUS_LUIDS_EXHAUSTED, -EIO, "STATUS_LUIDS_EXHAUSTED"},
- {STATUS_INVALID_SUB_AUTHORITY, -EIO, "STATUS_INVALID_SUB_AUTHORITY"},
- {STATUS_INVALID_ACL, -EIO, "STATUS_INVALID_ACL"},
- {STATUS_INVALID_SID, -EIO, "STATUS_INVALID_SID"},
- {STATUS_INVALID_SECURITY_DESCR, -EIO, "STATUS_INVALID_SECURITY_DESCR"},
- {STATUS_PROCEDURE_NOT_FOUND, -EIO, "STATUS_PROCEDURE_NOT_FOUND"},
- {STATUS_INVALID_IMAGE_FORMAT, -EIO, "STATUS_INVALID_IMAGE_FORMAT"},
- {STATUS_NO_TOKEN, -EIO, "STATUS_NO_TOKEN"},
- {STATUS_BAD_INHERITANCE_ACL, -EIO, "STATUS_BAD_INHERITANCE_ACL"},
- {STATUS_RANGE_NOT_LOCKED, -EIO, "STATUS_RANGE_NOT_LOCKED"},
- {STATUS_DISK_FULL, -ENOSPC, "STATUS_DISK_FULL"},
- {STATUS_SERVER_DISABLED, -EIO, "STATUS_SERVER_DISABLED"},
- {STATUS_SERVER_NOT_DISABLED, -EIO, "STATUS_SERVER_NOT_DISABLED"},
- {STATUS_TOO_MANY_GUIDS_REQUESTED, -EIO,
- "STATUS_TOO_MANY_GUIDS_REQUESTED"},
- {STATUS_GUIDS_EXHAUSTED, -EIO, "STATUS_GUIDS_EXHAUSTED"},
- {STATUS_INVALID_ID_AUTHORITY, -EIO, "STATUS_INVALID_ID_AUTHORITY"},
- {STATUS_AGENTS_EXHAUSTED, -EIO, "STATUS_AGENTS_EXHAUSTED"},
- {STATUS_INVALID_VOLUME_LABEL, -EIO, "STATUS_INVALID_VOLUME_LABEL"},
- {STATUS_SECTION_NOT_EXTENDED, -EIO, "STATUS_SECTION_NOT_EXTENDED"},
- {STATUS_NOT_MAPPED_DATA, -EIO, "STATUS_NOT_MAPPED_DATA"},
- {STATUS_RESOURCE_DATA_NOT_FOUND, -EIO,
- "STATUS_RESOURCE_DATA_NOT_FOUND"},
- {STATUS_RESOURCE_TYPE_NOT_FOUND, -EIO,
- "STATUS_RESOURCE_TYPE_NOT_FOUND"},
- {STATUS_RESOURCE_NAME_NOT_FOUND, -EIO,
- "STATUS_RESOURCE_NAME_NOT_FOUND"},
- {STATUS_ARRAY_BOUNDS_EXCEEDED, -EIO, "STATUS_ARRAY_BOUNDS_EXCEEDED"},
- {STATUS_FLOAT_DENORMAL_OPERAND, -EIO, "STATUS_FLOAT_DENORMAL_OPERAND"},
- {STATUS_FLOAT_DIVIDE_BY_ZERO, -EIO, "STATUS_FLOAT_DIVIDE_BY_ZERO"},
- {STATUS_FLOAT_INEXACT_RESULT, -EIO, "STATUS_FLOAT_INEXACT_RESULT"},
- {STATUS_FLOAT_INVALID_OPERATION, -EIO,
- "STATUS_FLOAT_INVALID_OPERATION"},
- {STATUS_FLOAT_OVERFLOW, -EIO, "STATUS_FLOAT_OVERFLOW"},
- {STATUS_FLOAT_STACK_CHECK, -EIO, "STATUS_FLOAT_STACK_CHECK"},
- {STATUS_FLOAT_UNDERFLOW, -EIO, "STATUS_FLOAT_UNDERFLOW"},
- {STATUS_INTEGER_DIVIDE_BY_ZERO, -EIO, "STATUS_INTEGER_DIVIDE_BY_ZERO"},
- {STATUS_INTEGER_OVERFLOW, -EIO, "STATUS_INTEGER_OVERFLOW"},
- {STATUS_PRIVILEGED_INSTRUCTION, -EIO, "STATUS_PRIVILEGED_INSTRUCTION"},
- {STATUS_TOO_MANY_PAGING_FILES, -EIO, "STATUS_TOO_MANY_PAGING_FILES"},
- {STATUS_FILE_INVALID, -EIO, "STATUS_FILE_INVALID"},
- {STATUS_ALLOTTED_SPACE_EXCEEDED, -EIO,
- "STATUS_ALLOTTED_SPACE_EXCEEDED"},
- {STATUS_INSUFFICIENT_RESOURCES, -EAGAIN,
- "STATUS_INSUFFICIENT_RESOURCES"},
- {STATUS_DFS_EXIT_PATH_FOUND, -EIO, "STATUS_DFS_EXIT_PATH_FOUND"},
- {STATUS_DEVICE_DATA_ERROR, -EIO, "STATUS_DEVICE_DATA_ERROR"},
- {STATUS_DEVICE_NOT_CONNECTED, -EIO, "STATUS_DEVICE_NOT_CONNECTED"},
- {STATUS_DEVICE_POWER_FAILURE, -EIO, "STATUS_DEVICE_POWER_FAILURE"},
- {STATUS_FREE_VM_NOT_AT_BASE, -EIO, "STATUS_FREE_VM_NOT_AT_BASE"},
- {STATUS_MEMORY_NOT_ALLOCATED, -EFAULT, "STATUS_MEMORY_NOT_ALLOCATED"},
- {STATUS_WORKING_SET_QUOTA, -EIO, "STATUS_WORKING_SET_QUOTA"},
- {STATUS_MEDIA_WRITE_PROTECTED, -EROFS, "STATUS_MEDIA_WRITE_PROTECTED"},
- {STATUS_DEVICE_NOT_READY, -EIO, "STATUS_DEVICE_NOT_READY"},
- {STATUS_INVALID_GROUP_ATTRIBUTES, -EIO,
- "STATUS_INVALID_GROUP_ATTRIBUTES"},
- {STATUS_BAD_IMPERSONATION_LEVEL, -EIO,
- "STATUS_BAD_IMPERSONATION_LEVEL"},
- {STATUS_CANT_OPEN_ANONYMOUS, -EIO, "STATUS_CANT_OPEN_ANONYMOUS"},
- {STATUS_BAD_VALIDATION_CLASS, -EIO, "STATUS_BAD_VALIDATION_CLASS"},
- {STATUS_BAD_TOKEN_TYPE, -EIO, "STATUS_BAD_TOKEN_TYPE"},
- {STATUS_BAD_MASTER_BOOT_RECORD, -EIO, "STATUS_BAD_MASTER_BOOT_RECORD"},
- {STATUS_INSTRUCTION_MISALIGNMENT, -EIO,
- "STATUS_INSTRUCTION_MISALIGNMENT"},
- {STATUS_INSTANCE_NOT_AVAILABLE, -EIO, "STATUS_INSTANCE_NOT_AVAILABLE"},
- {STATUS_PIPE_NOT_AVAILABLE, -EIO, "STATUS_PIPE_NOT_AVAILABLE"},
- {STATUS_INVALID_PIPE_STATE, -EIO, "STATUS_INVALID_PIPE_STATE"},
- {STATUS_PIPE_BUSY, -EBUSY, "STATUS_PIPE_BUSY"},
- {STATUS_ILLEGAL_FUNCTION, -EIO, "STATUS_ILLEGAL_FUNCTION"},
- {STATUS_PIPE_DISCONNECTED, -EPIPE, "STATUS_PIPE_DISCONNECTED"},
- {STATUS_PIPE_CLOSING, -EIO, "STATUS_PIPE_CLOSING"},
- {STATUS_PIPE_CONNECTED, -EIO, "STATUS_PIPE_CONNECTED"},
- {STATUS_PIPE_LISTENING, -EIO, "STATUS_PIPE_LISTENING"},
- {STATUS_INVALID_READ_MODE, -EIO, "STATUS_INVALID_READ_MODE"},
- {STATUS_IO_TIMEOUT, -EAGAIN, "STATUS_IO_TIMEOUT"},
- {STATUS_FILE_FORCED_CLOSED, -EIO, "STATUS_FILE_FORCED_CLOSED"},
- {STATUS_PROFILING_NOT_STARTED, -EIO, "STATUS_PROFILING_NOT_STARTED"},
- {STATUS_PROFILING_NOT_STOPPED, -EIO, "STATUS_PROFILING_NOT_STOPPED"},
- {STATUS_COULD_NOT_INTERPRET, -EIO, "STATUS_COULD_NOT_INTERPRET"},
- {STATUS_FILE_IS_A_DIRECTORY, -EISDIR, "STATUS_FILE_IS_A_DIRECTORY"},
- {STATUS_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_NOT_SUPPORTED"},
- {STATUS_REMOTE_NOT_LISTENING, -EHOSTDOWN,
- "STATUS_REMOTE_NOT_LISTENING"},
- {STATUS_DUPLICATE_NAME, -ENOTUNIQ, "STATUS_DUPLICATE_NAME"},
- {STATUS_BAD_NETWORK_PATH, -EINVAL, "STATUS_BAD_NETWORK_PATH"},
- {STATUS_NETWORK_BUSY, -EBUSY, "STATUS_NETWORK_BUSY"},
- {STATUS_DEVICE_DOES_NOT_EXIST, -ENODEV, "STATUS_DEVICE_DOES_NOT_EXIST"},
- {STATUS_TOO_MANY_COMMANDS, -EIO, "STATUS_TOO_MANY_COMMANDS"},
- {STATUS_ADAPTER_HARDWARE_ERROR, -EIO, "STATUS_ADAPTER_HARDWARE_ERROR"},
- {STATUS_INVALID_NETWORK_RESPONSE, -EIO,
- "STATUS_INVALID_NETWORK_RESPONSE"},
- {STATUS_UNEXPECTED_NETWORK_ERROR, -EIO,
- "STATUS_UNEXPECTED_NETWORK_ERROR"},
- {STATUS_BAD_REMOTE_ADAPTER, -EIO, "STATUS_BAD_REMOTE_ADAPTER"},
- {STATUS_PRINT_QUEUE_FULL, -EIO, "STATUS_PRINT_QUEUE_FULL"},
- {STATUS_NO_SPOOL_SPACE, -EIO, "STATUS_NO_SPOOL_SPACE"},
- {STATUS_PRINT_CANCELLED, -EIO, "STATUS_PRINT_CANCELLED"},
- {STATUS_NETWORK_NAME_DELETED, -EREMCHG, "STATUS_NETWORK_NAME_DELETED"},
- {STATUS_NETWORK_ACCESS_DENIED, -EACCES, "STATUS_NETWORK_ACCESS_DENIED"},
- {STATUS_BAD_DEVICE_TYPE, -EIO, "STATUS_BAD_DEVICE_TYPE"},
- {STATUS_BAD_NETWORK_NAME, -ENOENT, "STATUS_BAD_NETWORK_NAME"},
- {STATUS_TOO_MANY_NAMES, -EIO, "STATUS_TOO_MANY_NAMES"},
- {STATUS_TOO_MANY_SESSIONS, -EIO, "STATUS_TOO_MANY_SESSIONS"},
- {STATUS_SHARING_PAUSED, -EIO, "STATUS_SHARING_PAUSED"},
- {STATUS_REQUEST_NOT_ACCEPTED, -EIO, "STATUS_REQUEST_NOT_ACCEPTED"},
- {STATUS_REDIRECTOR_PAUSED, -EIO, "STATUS_REDIRECTOR_PAUSED"},
- {STATUS_NET_WRITE_FAULT, -EIO, "STATUS_NET_WRITE_FAULT"},
- {STATUS_PROFILING_AT_LIMIT, -EIO, "STATUS_PROFILING_AT_LIMIT"},
- {STATUS_NOT_SAME_DEVICE, -EXDEV, "STATUS_NOT_SAME_DEVICE"},
- {STATUS_FILE_RENAMED, -EIO, "STATUS_FILE_RENAMED"},
- {STATUS_VIRTUAL_CIRCUIT_CLOSED, -EIO, "STATUS_VIRTUAL_CIRCUIT_CLOSED"},
- {STATUS_NO_SECURITY_ON_OBJECT, -EIO, "STATUS_NO_SECURITY_ON_OBJECT"},
- {STATUS_CANT_WAIT, -EIO, "STATUS_CANT_WAIT"},
- {STATUS_PIPE_EMPTY, -EIO, "STATUS_PIPE_EMPTY"},
- {STATUS_CANT_ACCESS_DOMAIN_INFO, -EIO,
- "STATUS_CANT_ACCESS_DOMAIN_INFO"},
- {STATUS_CANT_TERMINATE_SELF, -EIO, "STATUS_CANT_TERMINATE_SELF"},
- {STATUS_INVALID_SERVER_STATE, -EIO, "STATUS_INVALID_SERVER_STATE"},
- {STATUS_INVALID_DOMAIN_STATE, -EIO, "STATUS_INVALID_DOMAIN_STATE"},
- {STATUS_INVALID_DOMAIN_ROLE, -EIO, "STATUS_INVALID_DOMAIN_ROLE"},
- {STATUS_NO_SUCH_DOMAIN, -EIO, "STATUS_NO_SUCH_DOMAIN"},
- {STATUS_DOMAIN_EXISTS, -EIO, "STATUS_DOMAIN_EXISTS"},
- {STATUS_DOMAIN_LIMIT_EXCEEDED, -EIO, "STATUS_DOMAIN_LIMIT_EXCEEDED"},
- {STATUS_OPLOCK_NOT_GRANTED, -EIO, "STATUS_OPLOCK_NOT_GRANTED"},
- {STATUS_INVALID_OPLOCK_PROTOCOL, -EIO,
- "STATUS_INVALID_OPLOCK_PROTOCOL"},
- {STATUS_INTERNAL_DB_CORRUPTION, -EIO, "STATUS_INTERNAL_DB_CORRUPTION"},
- {STATUS_INTERNAL_ERROR, -EIO, "STATUS_INTERNAL_ERROR"},
- {STATUS_GENERIC_NOT_MAPPED, -EIO, "STATUS_GENERIC_NOT_MAPPED"},
- {STATUS_BAD_DESCRIPTOR_FORMAT, -EIO, "STATUS_BAD_DESCRIPTOR_FORMAT"},
- {STATUS_INVALID_USER_BUFFER, -EIO, "STATUS_INVALID_USER_BUFFER"},
- {STATUS_UNEXPECTED_IO_ERROR, -EIO, "STATUS_UNEXPECTED_IO_ERROR"},
- {STATUS_UNEXPECTED_MM_CREATE_ERR, -EIO,
- "STATUS_UNEXPECTED_MM_CREATE_ERR"},
- {STATUS_UNEXPECTED_MM_MAP_ERROR, -EIO,
- "STATUS_UNEXPECTED_MM_MAP_ERROR"},
- {STATUS_UNEXPECTED_MM_EXTEND_ERR, -EIO,
- "STATUS_UNEXPECTED_MM_EXTEND_ERR"},
- {STATUS_NOT_LOGON_PROCESS, -EIO, "STATUS_NOT_LOGON_PROCESS"},
- {STATUS_LOGON_SESSION_EXISTS, -EIO, "STATUS_LOGON_SESSION_EXISTS"},
- {STATUS_INVALID_PARAMETER_1, -EINVAL, "STATUS_INVALID_PARAMETER_1"},
- {STATUS_INVALID_PARAMETER_2, -EINVAL, "STATUS_INVALID_PARAMETER_2"},
- {STATUS_INVALID_PARAMETER_3, -EINVAL, "STATUS_INVALID_PARAMETER_3"},
- {STATUS_INVALID_PARAMETER_4, -EINVAL, "STATUS_INVALID_PARAMETER_4"},
- {STATUS_INVALID_PARAMETER_5, -EINVAL, "STATUS_INVALID_PARAMETER_5"},
- {STATUS_INVALID_PARAMETER_6, -EINVAL, "STATUS_INVALID_PARAMETER_6"},
- {STATUS_INVALID_PARAMETER_7, -EINVAL, "STATUS_INVALID_PARAMETER_7"},
- {STATUS_INVALID_PARAMETER_8, -EINVAL, "STATUS_INVALID_PARAMETER_8"},
- {STATUS_INVALID_PARAMETER_9, -EINVAL, "STATUS_INVALID_PARAMETER_9"},
- {STATUS_INVALID_PARAMETER_10, -EINVAL, "STATUS_INVALID_PARAMETER_10"},
- {STATUS_INVALID_PARAMETER_11, -EINVAL, "STATUS_INVALID_PARAMETER_11"},
- {STATUS_INVALID_PARAMETER_12, -EINVAL, "STATUS_INVALID_PARAMETER_12"},
- {STATUS_REDIRECTOR_NOT_STARTED, -EIO, "STATUS_REDIRECTOR_NOT_STARTED"},
- {STATUS_REDIRECTOR_STARTED, -EIO, "STATUS_REDIRECTOR_STARTED"},
- {STATUS_STACK_OVERFLOW, -EIO, "STATUS_STACK_OVERFLOW"},
- {STATUS_NO_SUCH_PACKAGE, -EIO, "STATUS_NO_SUCH_PACKAGE"},
- {STATUS_BAD_FUNCTION_TABLE, -EIO, "STATUS_BAD_FUNCTION_TABLE"},
- {STATUS_VARIABLE_NOT_FOUND, -EIO, "STATUS_VARIABLE_NOT_FOUND"},
- {STATUS_DIRECTORY_NOT_EMPTY, -ENOTEMPTY, "STATUS_DIRECTORY_NOT_EMPTY"},
- {STATUS_FILE_CORRUPT_ERROR, -EIO, "STATUS_FILE_CORRUPT_ERROR"},
- {STATUS_NOT_A_DIRECTORY, -ENOTDIR, "STATUS_NOT_A_DIRECTORY"},
- {STATUS_BAD_LOGON_SESSION_STATE, -EIO,
- "STATUS_BAD_LOGON_SESSION_STATE"},
- {STATUS_LOGON_SESSION_COLLISION, -EIO,
- "STATUS_LOGON_SESSION_COLLISION"},
- {STATUS_NAME_TOO_LONG, -ENAMETOOLONG, "STATUS_NAME_TOO_LONG"},
- {STATUS_FILES_OPEN, -EIO, "STATUS_FILES_OPEN"},
- {STATUS_CONNECTION_IN_USE, -EIO, "STATUS_CONNECTION_IN_USE"},
- {STATUS_MESSAGE_NOT_FOUND, -EIO, "STATUS_MESSAGE_NOT_FOUND"},
- {STATUS_PROCESS_IS_TERMINATING, -EIO, "STATUS_PROCESS_IS_TERMINATING"},
- {STATUS_INVALID_LOGON_TYPE, -EIO, "STATUS_INVALID_LOGON_TYPE"},
- {STATUS_NO_GUID_TRANSLATION, -EIO, "STATUS_NO_GUID_TRANSLATION"},
- {STATUS_CANNOT_IMPERSONATE, -EIO, "STATUS_CANNOT_IMPERSONATE"},
- {STATUS_IMAGE_ALREADY_LOADED, -EIO, "STATUS_IMAGE_ALREADY_LOADED"},
- {STATUS_ABIOS_NOT_PRESENT, -EIO, "STATUS_ABIOS_NOT_PRESENT"},
- {STATUS_ABIOS_LID_NOT_EXIST, -EIO, "STATUS_ABIOS_LID_NOT_EXIST"},
- {STATUS_ABIOS_LID_ALREADY_OWNED, -EIO,
- "STATUS_ABIOS_LID_ALREADY_OWNED"},
- {STATUS_ABIOS_NOT_LID_OWNER, -EIO, "STATUS_ABIOS_NOT_LID_OWNER"},
- {STATUS_ABIOS_INVALID_COMMAND, -EIO, "STATUS_ABIOS_INVALID_COMMAND"},
- {STATUS_ABIOS_INVALID_LID, -EIO, "STATUS_ABIOS_INVALID_LID"},
- {STATUS_ABIOS_SELECTOR_NOT_AVAILABLE, -EIO,
- "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE"},
- {STATUS_ABIOS_INVALID_SELECTOR, -EIO, "STATUS_ABIOS_INVALID_SELECTOR"},
- {STATUS_NO_LDT, -EIO, "STATUS_NO_LDT"},
- {STATUS_INVALID_LDT_SIZE, -EIO, "STATUS_INVALID_LDT_SIZE"},
- {STATUS_INVALID_LDT_OFFSET, -EIO, "STATUS_INVALID_LDT_OFFSET"},
- {STATUS_INVALID_LDT_DESCRIPTOR, -EIO, "STATUS_INVALID_LDT_DESCRIPTOR"},
- {STATUS_INVALID_IMAGE_NE_FORMAT, -EIO,
- "STATUS_INVALID_IMAGE_NE_FORMAT"},
- {STATUS_RXACT_INVALID_STATE, -EIO, "STATUS_RXACT_INVALID_STATE"},
- {STATUS_RXACT_COMMIT_FAILURE, -EIO, "STATUS_RXACT_COMMIT_FAILURE"},
- {STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"},
- {STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"},
- {STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"},
- {STATUS_CANNOT_DELETE, -EACCES, "STATUS_CANNOT_DELETE"},
- {STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"},
- {STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"},
- {STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"},
- {STATUS_SPECIAL_GROUP, -EIO, "STATUS_SPECIAL_GROUP"},
- {STATUS_SPECIAL_USER, -EIO, "STATUS_SPECIAL_USER"},
- {STATUS_MEMBERS_PRIMARY_GROUP, -EIO, "STATUS_MEMBERS_PRIMARY_GROUP"},
- {STATUS_FILE_CLOSED, -EBADF, "STATUS_FILE_CLOSED"},
- {STATUS_TOO_MANY_THREADS, -EIO, "STATUS_TOO_MANY_THREADS"},
- {STATUS_THREAD_NOT_IN_PROCESS, -EIO, "STATUS_THREAD_NOT_IN_PROCESS"},
- {STATUS_TOKEN_ALREADY_IN_USE, -EIO, "STATUS_TOKEN_ALREADY_IN_USE"},
- {STATUS_PAGEFILE_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_PAGEFILE_QUOTA_EXCEEDED"},
- {STATUS_COMMITMENT_LIMIT, -EIO, "STATUS_COMMITMENT_LIMIT"},
- {STATUS_INVALID_IMAGE_LE_FORMAT, -EIO,
- "STATUS_INVALID_IMAGE_LE_FORMAT"},
- {STATUS_INVALID_IMAGE_NOT_MZ, -EIO, "STATUS_INVALID_IMAGE_NOT_MZ"},
- {STATUS_INVALID_IMAGE_PROTECT, -EIO, "STATUS_INVALID_IMAGE_PROTECT"},
- {STATUS_INVALID_IMAGE_WIN_16, -EIO, "STATUS_INVALID_IMAGE_WIN_16"},
- {STATUS_LOGON_SERVER_CONFLICT, -EIO, "STATUS_LOGON_SERVER_CONFLICT"},
- {STATUS_TIME_DIFFERENCE_AT_DC, -EIO, "STATUS_TIME_DIFFERENCE_AT_DC"},
- {STATUS_SYNCHRONIZATION_REQUIRED, -EIO,
- "STATUS_SYNCHRONIZATION_REQUIRED"},
- {STATUS_DLL_NOT_FOUND, -ENOENT, "STATUS_DLL_NOT_FOUND"},
- {STATUS_OPEN_FAILED, -EIO, "STATUS_OPEN_FAILED"},
- {STATUS_IO_PRIVILEGE_FAILED, -EIO, "STATUS_IO_PRIVILEGE_FAILED"},
- {STATUS_ORDINAL_NOT_FOUND, -EIO, "STATUS_ORDINAL_NOT_FOUND"},
- {STATUS_ENTRYPOINT_NOT_FOUND, -EIO, "STATUS_ENTRYPOINT_NOT_FOUND"},
- {STATUS_CONTROL_C_EXIT, -EIO, "STATUS_CONTROL_C_EXIT"},
- {STATUS_LOCAL_DISCONNECT, -EIO, "STATUS_LOCAL_DISCONNECT"},
- {STATUS_REMOTE_DISCONNECT, -ESHUTDOWN, "STATUS_REMOTE_DISCONNECT"},
- {STATUS_REMOTE_RESOURCES, -EIO, "STATUS_REMOTE_RESOURCES"},
- {STATUS_LINK_FAILED, -EXDEV, "STATUS_LINK_FAILED"},
- {STATUS_LINK_TIMEOUT, -ETIMEDOUT, "STATUS_LINK_TIMEOUT"},
- {STATUS_INVALID_CONNECTION, -EIO, "STATUS_INVALID_CONNECTION"},
- {STATUS_INVALID_ADDRESS, -EIO, "STATUS_INVALID_ADDRESS"},
- {STATUS_DLL_INIT_FAILED, -EIO, "STATUS_DLL_INIT_FAILED"},
- {STATUS_MISSING_SYSTEMFILE, -EIO, "STATUS_MISSING_SYSTEMFILE"},
- {STATUS_UNHANDLED_EXCEPTION, -EIO, "STATUS_UNHANDLED_EXCEPTION"},
- {STATUS_APP_INIT_FAILURE, -EIO, "STATUS_APP_INIT_FAILURE"},
- {STATUS_PAGEFILE_CREATE_FAILED, -EIO, "STATUS_PAGEFILE_CREATE_FAILED"},
- {STATUS_NO_PAGEFILE, -EIO, "STATUS_NO_PAGEFILE"},
- {STATUS_INVALID_LEVEL, -EIO, "STATUS_INVALID_LEVEL"},
- {STATUS_WRONG_PASSWORD_CORE, -EIO, "STATUS_WRONG_PASSWORD_CORE"},
- {STATUS_ILLEGAL_FLOAT_CONTEXT, -EIO, "STATUS_ILLEGAL_FLOAT_CONTEXT"},
- {STATUS_PIPE_BROKEN, -EPIPE, "STATUS_PIPE_BROKEN"},
- {STATUS_REGISTRY_CORRUPT, -EIO, "STATUS_REGISTRY_CORRUPT"},
- {STATUS_REGISTRY_IO_FAILED, -EIO, "STATUS_REGISTRY_IO_FAILED"},
- {STATUS_NO_EVENT_PAIR, -EIO, "STATUS_NO_EVENT_PAIR"},
- {STATUS_UNRECOGNIZED_VOLUME, -EIO, "STATUS_UNRECOGNIZED_VOLUME"},
- {STATUS_SERIAL_NO_DEVICE_INITED, -EIO,
- "STATUS_SERIAL_NO_DEVICE_INITED"},
- {STATUS_NO_SUCH_ALIAS, -EIO, "STATUS_NO_SUCH_ALIAS"},
- {STATUS_MEMBER_NOT_IN_ALIAS, -EIO, "STATUS_MEMBER_NOT_IN_ALIAS"},
- {STATUS_MEMBER_IN_ALIAS, -EIO, "STATUS_MEMBER_IN_ALIAS"},
- {STATUS_ALIAS_EXISTS, -EIO, "STATUS_ALIAS_EXISTS"},
- {STATUS_LOGON_NOT_GRANTED, -EIO, "STATUS_LOGON_NOT_GRANTED"},
- {STATUS_TOO_MANY_SECRETS, -EIO, "STATUS_TOO_MANY_SECRETS"},
- {STATUS_SECRET_TOO_LONG, -EIO, "STATUS_SECRET_TOO_LONG"},
- {STATUS_INTERNAL_DB_ERROR, -EIO, "STATUS_INTERNAL_DB_ERROR"},
- {STATUS_FULLSCREEN_MODE, -EIO, "STATUS_FULLSCREEN_MODE"},
- {STATUS_TOO_MANY_CONTEXT_IDS, -EIO, "STATUS_TOO_MANY_CONTEXT_IDS"},
- {STATUS_LOGON_TYPE_NOT_GRANTED, -EIO, "STATUS_LOGON_TYPE_NOT_GRANTED"},
- {STATUS_NOT_REGISTRY_FILE, -EIO, "STATUS_NOT_REGISTRY_FILE"},
- {STATUS_NT_CROSS_ENCRYPTION_REQUIRED, -EIO,
- "STATUS_NT_CROSS_ENCRYPTION_REQUIRED"},
- {STATUS_DOMAIN_CTRLR_CONFIG_ERROR, -EIO,
- "STATUS_DOMAIN_CTRLR_CONFIG_ERROR"},
- {STATUS_FT_MISSING_MEMBER, -EIO, "STATUS_FT_MISSING_MEMBER"},
- {STATUS_ILL_FORMED_SERVICE_ENTRY, -EIO,
- "STATUS_ILL_FORMED_SERVICE_ENTRY"},
- {STATUS_ILLEGAL_CHARACTER, -EIO, "STATUS_ILLEGAL_CHARACTER"},
- {STATUS_UNMAPPABLE_CHARACTER, -EIO, "STATUS_UNMAPPABLE_CHARACTER"},
- {STATUS_UNDEFINED_CHARACTER, -EIO, "STATUS_UNDEFINED_CHARACTER"},
- {STATUS_FLOPPY_VOLUME, -EIO, "STATUS_FLOPPY_VOLUME"},
- {STATUS_FLOPPY_ID_MARK_NOT_FOUND, -EIO,
- "STATUS_FLOPPY_ID_MARK_NOT_FOUND"},
- {STATUS_FLOPPY_WRONG_CYLINDER, -EIO, "STATUS_FLOPPY_WRONG_CYLINDER"},
- {STATUS_FLOPPY_UNKNOWN_ERROR, -EIO, "STATUS_FLOPPY_UNKNOWN_ERROR"},
- {STATUS_FLOPPY_BAD_REGISTERS, -EIO, "STATUS_FLOPPY_BAD_REGISTERS"},
- {STATUS_DISK_RECALIBRATE_FAILED, -EIO,
- "STATUS_DISK_RECALIBRATE_FAILED"},
- {STATUS_DISK_OPERATION_FAILED, -EIO, "STATUS_DISK_OPERATION_FAILED"},
- {STATUS_DISK_RESET_FAILED, -EIO, "STATUS_DISK_RESET_FAILED"},
- {STATUS_SHARED_IRQ_BUSY, -EBUSY, "STATUS_SHARED_IRQ_BUSY"},
- {STATUS_FT_ORPHANING, -EIO, "STATUS_FT_ORPHANING"},
- {STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT, -EIO,
- "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT"},
- {STATUS_PARTITION_FAILURE, -EIO, "STATUS_PARTITION_FAILURE"},
- {STATUS_INVALID_BLOCK_LENGTH, -EIO, "STATUS_INVALID_BLOCK_LENGTH"},
- {STATUS_DEVICE_NOT_PARTITIONED, -EIO, "STATUS_DEVICE_NOT_PARTITIONED"},
- {STATUS_UNABLE_TO_LOCK_MEDIA, -EIO, "STATUS_UNABLE_TO_LOCK_MEDIA"},
- {STATUS_UNABLE_TO_UNLOAD_MEDIA, -EIO, "STATUS_UNABLE_TO_UNLOAD_MEDIA"},
- {STATUS_EOM_OVERFLOW, -EIO, "STATUS_EOM_OVERFLOW"},
- {STATUS_NO_MEDIA, -EIO, "STATUS_NO_MEDIA"},
- {STATUS_NO_SUCH_MEMBER, -EIO, "STATUS_NO_SUCH_MEMBER"},
- {STATUS_INVALID_MEMBER, -EIO, "STATUS_INVALID_MEMBER"},
- {STATUS_KEY_DELETED, -EIO, "STATUS_KEY_DELETED"},
- {STATUS_NO_LOG_SPACE, -EIO, "STATUS_NO_LOG_SPACE"},
- {STATUS_TOO_MANY_SIDS, -EIO, "STATUS_TOO_MANY_SIDS"},
- {STATUS_LM_CROSS_ENCRYPTION_REQUIRED, -EIO,
- "STATUS_LM_CROSS_ENCRYPTION_REQUIRED"},
- {STATUS_KEY_HAS_CHILDREN, -EIO, "STATUS_KEY_HAS_CHILDREN"},
- {STATUS_CHILD_MUST_BE_VOLATILE, -EIO, "STATUS_CHILD_MUST_BE_VOLATILE"},
- {STATUS_DEVICE_CONFIGURATION_ERROR, -EIO,
- "STATUS_DEVICE_CONFIGURATION_ERROR"},
- {STATUS_DRIVER_INTERNAL_ERROR, -EIO, "STATUS_DRIVER_INTERNAL_ERROR"},
- {STATUS_INVALID_DEVICE_STATE, -EIO, "STATUS_INVALID_DEVICE_STATE"},
- {STATUS_IO_DEVICE_ERROR, -EIO, "STATUS_IO_DEVICE_ERROR"},
- {STATUS_DEVICE_PROTOCOL_ERROR, -EIO, "STATUS_DEVICE_PROTOCOL_ERROR"},
- {STATUS_BACKUP_CONTROLLER, -EIO, "STATUS_BACKUP_CONTROLLER"},
- {STATUS_LOG_FILE_FULL, -EIO, "STATUS_LOG_FILE_FULL"},
- {STATUS_TOO_LATE, -EIO, "STATUS_TOO_LATE"},
- {STATUS_NO_TRUST_LSA_SECRET, -EIO, "STATUS_NO_TRUST_LSA_SECRET"},
- {STATUS_NO_TRUST_SAM_ACCOUNT, -EIO, "STATUS_NO_TRUST_SAM_ACCOUNT"},
- {STATUS_TRUSTED_DOMAIN_FAILURE, -EIO, "STATUS_TRUSTED_DOMAIN_FAILURE"},
- {STATUS_TRUSTED_RELATIONSHIP_FAILURE, -EIO,
- "STATUS_TRUSTED_RELATIONSHIP_FAILURE"},
- {STATUS_EVENTLOG_FILE_CORRUPT, -EIO, "STATUS_EVENTLOG_FILE_CORRUPT"},
- {STATUS_EVENTLOG_CANT_START, -EIO, "STATUS_EVENTLOG_CANT_START"},
- {STATUS_TRUST_FAILURE, -EIO, "STATUS_TRUST_FAILURE"},
- {STATUS_MUTANT_LIMIT_EXCEEDED, -EIO, "STATUS_MUTANT_LIMIT_EXCEEDED"},
- {STATUS_NETLOGON_NOT_STARTED, -EIO, "STATUS_NETLOGON_NOT_STARTED"},
- {STATUS_ACCOUNT_EXPIRED, -EKEYEXPIRED, "STATUS_ACCOUNT_EXPIRED"},
- {STATUS_POSSIBLE_DEADLOCK, -EIO, "STATUS_POSSIBLE_DEADLOCK"},
- {STATUS_NETWORK_CREDENTIAL_CONFLICT, -EIO,
- "STATUS_NETWORK_CREDENTIAL_CONFLICT"},
- {STATUS_REMOTE_SESSION_LIMIT, -EIO, "STATUS_REMOTE_SESSION_LIMIT"},
- {STATUS_EVENTLOG_FILE_CHANGED, -EIO, "STATUS_EVENTLOG_FILE_CHANGED"},
- {STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, -EIO,
- "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"},
- {STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, -EIO,
- "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"},
- {STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, -EIO,
- "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"},
- {STATUS_DOMAIN_TRUST_INCONSISTENT, -EIO,
- "STATUS_DOMAIN_TRUST_INCONSISTENT"},
- {STATUS_FS_DRIVER_REQUIRED, -EOPNOTSUPP, "STATUS_FS_DRIVER_REQUIRED"},
- {STATUS_IMAGE_ALREADY_LOADED_AS_DLL, -EIO,
- "STATUS_IMAGE_ALREADY_LOADED_AS_DLL"},
- {STATUS_NETWORK_OPEN_RESTRICTION, -EIO,
- "STATUS_NETWORK_OPEN_RESTRICTION"},
- {STATUS_NO_USER_SESSION_KEY, -EIO, "STATUS_NO_USER_SESSION_KEY"},
- {STATUS_USER_SESSION_DELETED, -EIO, "STATUS_USER_SESSION_DELETED"},
- {STATUS_RESOURCE_LANG_NOT_FOUND, -EIO,
- "STATUS_RESOURCE_LANG_NOT_FOUND"},
- {STATUS_INSUFF_SERVER_RESOURCES, -EIO,
- "STATUS_INSUFF_SERVER_RESOURCES"},
- {STATUS_INVALID_BUFFER_SIZE, -EIO, "STATUS_INVALID_BUFFER_SIZE"},
- {STATUS_INVALID_ADDRESS_COMPONENT, -EIO,
- "STATUS_INVALID_ADDRESS_COMPONENT"},
- {STATUS_INVALID_ADDRESS_WILDCARD, -EIO,
- "STATUS_INVALID_ADDRESS_WILDCARD"},
- {STATUS_TOO_MANY_ADDRESSES, -EIO, "STATUS_TOO_MANY_ADDRESSES"},
- {STATUS_ADDRESS_ALREADY_EXISTS, -EADDRINUSE,
- "STATUS_ADDRESS_ALREADY_EXISTS"},
- {STATUS_ADDRESS_CLOSED, -EIO, "STATUS_ADDRESS_CLOSED"},
- {STATUS_CONNECTION_DISCONNECTED, -ECONNABORTED,
- "STATUS_CONNECTION_DISCONNECTED"},
- {STATUS_CONNECTION_RESET, -ENETRESET, "STATUS_CONNECTION_RESET"},
- {STATUS_TOO_MANY_NODES, -EIO, "STATUS_TOO_MANY_NODES"},
- {STATUS_TRANSACTION_ABORTED, -EIO, "STATUS_TRANSACTION_ABORTED"},
- {STATUS_TRANSACTION_TIMED_OUT, -EIO, "STATUS_TRANSACTION_TIMED_OUT"},
- {STATUS_TRANSACTION_NO_RELEASE, -EIO, "STATUS_TRANSACTION_NO_RELEASE"},
- {STATUS_TRANSACTION_NO_MATCH, -EIO, "STATUS_TRANSACTION_NO_MATCH"},
- {STATUS_TRANSACTION_RESPONDED, -EIO, "STATUS_TRANSACTION_RESPONDED"},
- {STATUS_TRANSACTION_INVALID_ID, -EIO, "STATUS_TRANSACTION_INVALID_ID"},
- {STATUS_TRANSACTION_INVALID_TYPE, -EIO,
- "STATUS_TRANSACTION_INVALID_TYPE"},
- {STATUS_NOT_SERVER_SESSION, -EIO, "STATUS_NOT_SERVER_SESSION"},
- {STATUS_NOT_CLIENT_SESSION, -EIO, "STATUS_NOT_CLIENT_SESSION"},
- {STATUS_CANNOT_LOAD_REGISTRY_FILE, -EIO,
- "STATUS_CANNOT_LOAD_REGISTRY_FILE"},
- {STATUS_DEBUG_ATTACH_FAILED, -EIO, "STATUS_DEBUG_ATTACH_FAILED"},
- {STATUS_SYSTEM_PROCESS_TERMINATED, -EIO,
- "STATUS_SYSTEM_PROCESS_TERMINATED"},
- {STATUS_DATA_NOT_ACCEPTED, -EIO, "STATUS_DATA_NOT_ACCEPTED"},
- {STATUS_NO_BROWSER_SERVERS_FOUND, -EIO,
- "STATUS_NO_BROWSER_SERVERS_FOUND"},
- {STATUS_VDM_HARD_ERROR, -EIO, "STATUS_VDM_HARD_ERROR"},
- {STATUS_DRIVER_CANCEL_TIMEOUT, -EIO, "STATUS_DRIVER_CANCEL_TIMEOUT"},
- {STATUS_REPLY_MESSAGE_MISMATCH, -EIO, "STATUS_REPLY_MESSAGE_MISMATCH"},
- {STATUS_MAPPED_ALIGNMENT, -EIO, "STATUS_MAPPED_ALIGNMENT"},
- {STATUS_IMAGE_CHECKSUM_MISMATCH, -EIO,
- "STATUS_IMAGE_CHECKSUM_MISMATCH"},
- {STATUS_LOST_WRITEBEHIND_DATA, -EIO, "STATUS_LOST_WRITEBEHIND_DATA"},
- {STATUS_CLIENT_SERVER_PARAMETERS_INVALID, -EIO,
- "STATUS_CLIENT_SERVER_PARAMETERS_INVALID"},
- {STATUS_PASSWORD_MUST_CHANGE, -EIO, "STATUS_PASSWORD_MUST_CHANGE"},
- {STATUS_NOT_FOUND, -ENOENT, "STATUS_NOT_FOUND"},
- {STATUS_NOT_TINY_STREAM, -EIO, "STATUS_NOT_TINY_STREAM"},
- {STATUS_RECOVERY_FAILURE, -EIO, "STATUS_RECOVERY_FAILURE"},
- {STATUS_STACK_OVERFLOW_READ, -EIO, "STATUS_STACK_OVERFLOW_READ"},
- {STATUS_FAIL_CHECK, -EIO, "STATUS_FAIL_CHECK"},
- {STATUS_DUPLICATE_OBJECTID, -EIO, "STATUS_DUPLICATE_OBJECTID"},
- {STATUS_OBJECTID_EXISTS, -EIO, "STATUS_OBJECTID_EXISTS"},
- {STATUS_CONVERT_TO_LARGE, -EIO, "STATUS_CONVERT_TO_LARGE"},
- {STATUS_RETRY, -EAGAIN, "STATUS_RETRY"},
- {STATUS_FOUND_OUT_OF_SCOPE, -EIO, "STATUS_FOUND_OUT_OF_SCOPE"},
- {STATUS_ALLOCATE_BUCKET, -EIO, "STATUS_ALLOCATE_BUCKET"},
- {STATUS_PROPSET_NOT_FOUND, -EIO, "STATUS_PROPSET_NOT_FOUND"},
- {STATUS_MARSHALL_OVERFLOW, -EIO, "STATUS_MARSHALL_OVERFLOW"},
- {STATUS_INVALID_VARIANT, -EIO, "STATUS_INVALID_VARIANT"},
- {STATUS_DOMAIN_CONTROLLER_NOT_FOUND, -EIO,
- "STATUS_DOMAIN_CONTROLLER_NOT_FOUND"},
- {STATUS_ACCOUNT_LOCKED_OUT, -EACCES, "STATUS_ACCOUNT_LOCKED_OUT"},
- {STATUS_HANDLE_NOT_CLOSABLE, -EIO, "STATUS_HANDLE_NOT_CLOSABLE"},
- {STATUS_CONNECTION_REFUSED, -EIO, "STATUS_CONNECTION_REFUSED"},
- {STATUS_GRACEFUL_DISCONNECT, -EIO, "STATUS_GRACEFUL_DISCONNECT"},
- {STATUS_ADDRESS_ALREADY_ASSOCIATED, -EIO,
- "STATUS_ADDRESS_ALREADY_ASSOCIATED"},
- {STATUS_ADDRESS_NOT_ASSOCIATED, -EIO, "STATUS_ADDRESS_NOT_ASSOCIATED"},
- {STATUS_CONNECTION_INVALID, -EIO, "STATUS_CONNECTION_INVALID"},
- {STATUS_CONNECTION_ACTIVE, -EIO, "STATUS_CONNECTION_ACTIVE"},
- {STATUS_NETWORK_UNREACHABLE, -ENETUNREACH,
- "STATUS_NETWORK_UNREACHABLE"},
- {STATUS_HOST_UNREACHABLE, -EHOSTDOWN, "STATUS_HOST_UNREACHABLE"},
- {STATUS_PROTOCOL_UNREACHABLE, -ENETUNREACH,
- "STATUS_PROTOCOL_UNREACHABLE"},
- {STATUS_PORT_UNREACHABLE, -ENETUNREACH, "STATUS_PORT_UNREACHABLE"},
- {STATUS_REQUEST_ABORTED, -EIO, "STATUS_REQUEST_ABORTED"},
- {STATUS_CONNECTION_ABORTED, -ECONNABORTED, "STATUS_CONNECTION_ABORTED"},
- {STATUS_BAD_COMPRESSION_BUFFER, -EIO, "STATUS_BAD_COMPRESSION_BUFFER"},
- {STATUS_USER_MAPPED_FILE, -EIO, "STATUS_USER_MAPPED_FILE"},
- {STATUS_AUDIT_FAILED, -EIO, "STATUS_AUDIT_FAILED"},
- {STATUS_TIMER_RESOLUTION_NOT_SET, -EIO,
- "STATUS_TIMER_RESOLUTION_NOT_SET"},
- {STATUS_CONNECTION_COUNT_LIMIT, -EIO, "STATUS_CONNECTION_COUNT_LIMIT"},
- {STATUS_LOGIN_TIME_RESTRICTION, -EACCES,
- "STATUS_LOGIN_TIME_RESTRICTION"},
- {STATUS_LOGIN_WKSTA_RESTRICTION, -EACCES,
- "STATUS_LOGIN_WKSTA_RESTRICTION"},
- {STATUS_IMAGE_MP_UP_MISMATCH, -EIO, "STATUS_IMAGE_MP_UP_MISMATCH"},
- {STATUS_INSUFFICIENT_LOGON_INFO, -EIO,
- "STATUS_INSUFFICIENT_LOGON_INFO"},
- {STATUS_BAD_DLL_ENTRYPOINT, -EIO, "STATUS_BAD_DLL_ENTRYPOINT"},
- {STATUS_BAD_SERVICE_ENTRYPOINT, -EIO, "STATUS_BAD_SERVICE_ENTRYPOINT"},
- {STATUS_LPC_REPLY_LOST, -EIO, "STATUS_LPC_REPLY_LOST"},
- {STATUS_IP_ADDRESS_CONFLICT1, -EIO, "STATUS_IP_ADDRESS_CONFLICT1"},
- {STATUS_IP_ADDRESS_CONFLICT2, -EIO, "STATUS_IP_ADDRESS_CONFLICT2"},
- {STATUS_REGISTRY_QUOTA_LIMIT, -EDQUOT, "STATUS_REGISTRY_QUOTA_LIMIT"},
- {STATUS_PATH_NOT_COVERED, -EREMOTE, "STATUS_PATH_NOT_COVERED"},
- {STATUS_NO_CALLBACK_ACTIVE, -EIO, "STATUS_NO_CALLBACK_ACTIVE"},
- {STATUS_LICENSE_QUOTA_EXCEEDED, -EACCES,
- "STATUS_LICENSE_QUOTA_EXCEEDED"},
- {STATUS_PWD_TOO_SHORT, -EIO, "STATUS_PWD_TOO_SHORT"},
- {STATUS_PWD_TOO_RECENT, -EIO, "STATUS_PWD_TOO_RECENT"},
- {STATUS_PWD_HISTORY_CONFLICT, -EIO, "STATUS_PWD_HISTORY_CONFLICT"},
- {STATUS_PLUGPLAY_NO_DEVICE, -EIO, "STATUS_PLUGPLAY_NO_DEVICE"},
- {STATUS_UNSUPPORTED_COMPRESSION, -EIO,
- "STATUS_UNSUPPORTED_COMPRESSION"},
- {STATUS_INVALID_HW_PROFILE, -EIO, "STATUS_INVALID_HW_PROFILE"},
- {STATUS_INVALID_PLUGPLAY_DEVICE_PATH, -EIO,
- "STATUS_INVALID_PLUGPLAY_DEVICE_PATH"},
- {STATUS_DRIVER_ORDINAL_NOT_FOUND, -EIO,
- "STATUS_DRIVER_ORDINAL_NOT_FOUND"},
- {STATUS_DRIVER_ENTRYPOINT_NOT_FOUND, -EIO,
- "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"},
- {STATUS_RESOURCE_NOT_OWNED, -EIO, "STATUS_RESOURCE_NOT_OWNED"},
- {STATUS_TOO_MANY_LINKS, -EMLINK, "STATUS_TOO_MANY_LINKS"},
- {STATUS_QUOTA_LIST_INCONSISTENT, -EIO,
- "STATUS_QUOTA_LIST_INCONSISTENT"},
- {STATUS_FILE_IS_OFFLINE, -EIO, "STATUS_FILE_IS_OFFLINE"},
- {STATUS_EVALUATION_EXPIRATION, -EIO, "STATUS_EVALUATION_EXPIRATION"},
- {STATUS_ILLEGAL_DLL_RELOCATION, -EIO, "STATUS_ILLEGAL_DLL_RELOCATION"},
- {STATUS_LICENSE_VIOLATION, -EIO, "STATUS_LICENSE_VIOLATION"},
- {STATUS_DLL_INIT_FAILED_LOGOFF, -EIO, "STATUS_DLL_INIT_FAILED_LOGOFF"},
- {STATUS_DRIVER_UNABLE_TO_LOAD, -EIO, "STATUS_DRIVER_UNABLE_TO_LOAD"},
- {STATUS_DFS_UNAVAILABLE, -EIO, "STATUS_DFS_UNAVAILABLE"},
- {STATUS_VOLUME_DISMOUNTED, -EIO, "STATUS_VOLUME_DISMOUNTED"},
- {STATUS_WX86_INTERNAL_ERROR, -EIO, "STATUS_WX86_INTERNAL_ERROR"},
- {STATUS_WX86_FLOAT_STACK_CHECK, -EIO, "STATUS_WX86_FLOAT_STACK_CHECK"},
- {STATUS_VALIDATE_CONTINUE, -EIO, "STATUS_VALIDATE_CONTINUE"},
- {STATUS_NO_MATCH, -EIO, "STATUS_NO_MATCH"},
- {STATUS_NO_MORE_MATCHES, -EIO, "STATUS_NO_MORE_MATCHES"},
- {STATUS_NOT_A_REPARSE_POINT, -ENODATA, "STATUS_NOT_A_REPARSE_POINT"},
- {STATUS_IO_REPARSE_TAG_INVALID, -EIO, "STATUS_IO_REPARSE_TAG_INVALID"},
- {STATUS_IO_REPARSE_TAG_MISMATCH, -EIO,
- "STATUS_IO_REPARSE_TAG_MISMATCH"},
- {STATUS_IO_REPARSE_DATA_INVALID, -EIO,
- "STATUS_IO_REPARSE_DATA_INVALID"},
- {STATUS_REPARSE_POINT_NOT_RESOLVED, -EIO,
- "STATUS_REPARSE_POINT_NOT_RESOLVED"},
- {STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO,
- "STATUS_DIRECTORY_IS_A_REPARSE_POINT"},
- {STATUS_RANGE_LIST_CONFLICT, -EIO, "STATUS_RANGE_LIST_CONFLICT"},
- {STATUS_SOURCE_ELEMENT_EMPTY, -EIO, "STATUS_SOURCE_ELEMENT_EMPTY"},
- {STATUS_DESTINATION_ELEMENT_FULL, -EIO,
- "STATUS_DESTINATION_ELEMENT_FULL"},
- {STATUS_ILLEGAL_ELEMENT_ADDRESS, -EIO,
- "STATUS_ILLEGAL_ELEMENT_ADDRESS"},
- {STATUS_MAGAZINE_NOT_PRESENT, -EIO, "STATUS_MAGAZINE_NOT_PRESENT"},
- {STATUS_REINITIALIZATION_NEEDED, -EIO,
- "STATUS_REINITIALIZATION_NEEDED"},
- {STATUS_ENCRYPTION_FAILED, -EIO, "STATUS_ENCRYPTION_FAILED"},
- {STATUS_DECRYPTION_FAILED, -EIO, "STATUS_DECRYPTION_FAILED"},
- {STATUS_RANGE_NOT_FOUND, -EIO, "STATUS_RANGE_NOT_FOUND"},
- {STATUS_NO_RECOVERY_POLICY, -EIO, "STATUS_NO_RECOVERY_POLICY"},
- {STATUS_NO_EFS, -EIO, "STATUS_NO_EFS"},
- {STATUS_WRONG_EFS, -EIO, "STATUS_WRONG_EFS"},
- {STATUS_NO_USER_KEYS, -EIO, "STATUS_NO_USER_KEYS"},
- {STATUS_FILE_NOT_ENCRYPTED, -EIO, "STATUS_FILE_NOT_ENCRYPTED"},
- {STATUS_NOT_EXPORT_FORMAT, -EIO, "STATUS_NOT_EXPORT_FORMAT"},
- {STATUS_FILE_ENCRYPTED, -EIO, "STATUS_FILE_ENCRYPTED"},
- {STATUS_WMI_GUID_NOT_FOUND, -EIO, "STATUS_WMI_GUID_NOT_FOUND"},
- {STATUS_WMI_INSTANCE_NOT_FOUND, -EIO, "STATUS_WMI_INSTANCE_NOT_FOUND"},
- {STATUS_WMI_ITEMID_NOT_FOUND, -EIO, "STATUS_WMI_ITEMID_NOT_FOUND"},
- {STATUS_WMI_TRY_AGAIN, -EIO, "STATUS_WMI_TRY_AGAIN"},
- {STATUS_SHARED_POLICY, -EIO, "STATUS_SHARED_POLICY"},
- {STATUS_POLICY_OBJECT_NOT_FOUND, -EIO,
- "STATUS_POLICY_OBJECT_NOT_FOUND"},
- {STATUS_POLICY_ONLY_IN_DS, -EIO, "STATUS_POLICY_ONLY_IN_DS"},
- {STATUS_VOLUME_NOT_UPGRADED, -EIO, "STATUS_VOLUME_NOT_UPGRADED"},
- {STATUS_REMOTE_STORAGE_NOT_ACTIVE, -EIO,
- "STATUS_REMOTE_STORAGE_NOT_ACTIVE"},
- {STATUS_REMOTE_STORAGE_MEDIA_ERROR, -EIO,
- "STATUS_REMOTE_STORAGE_MEDIA_ERROR"},
- {STATUS_NO_TRACKING_SERVICE, -EIO, "STATUS_NO_TRACKING_SERVICE"},
- {STATUS_SERVER_SID_MISMATCH, -EIO, "STATUS_SERVER_SID_MISMATCH"},
- {STATUS_DS_NO_ATTRIBUTE_OR_VALUE, -EIO,
- "STATUS_DS_NO_ATTRIBUTE_OR_VALUE"},
- {STATUS_DS_INVALID_ATTRIBUTE_SYNTAX, -EIO,
- "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"},
- {STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED, -EIO,
- "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"},
- {STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS, -EIO,
- "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"},
- {STATUS_DS_BUSY, -EBUSY, "STATUS_DS_BUSY"},
- {STATUS_DS_UNAVAILABLE, -EIO, "STATUS_DS_UNAVAILABLE"},
- {STATUS_DS_NO_RIDS_ALLOCATED, -EIO, "STATUS_DS_NO_RIDS_ALLOCATED"},
- {STATUS_DS_NO_MORE_RIDS, -EIO, "STATUS_DS_NO_MORE_RIDS"},
- {STATUS_DS_INCORRECT_ROLE_OWNER, -EIO,
- "STATUS_DS_INCORRECT_ROLE_OWNER"},
- {STATUS_DS_RIDMGR_INIT_ERROR, -EIO, "STATUS_DS_RIDMGR_INIT_ERROR"},
- {STATUS_DS_OBJ_CLASS_VIOLATION, -EIO, "STATUS_DS_OBJ_CLASS_VIOLATION"},
- {STATUS_DS_CANT_ON_NON_LEAF, -EIO, "STATUS_DS_CANT_ON_NON_LEAF"},
- {STATUS_DS_CANT_ON_RDN, -EIO, "STATUS_DS_CANT_ON_RDN"},
- {STATUS_DS_CANT_MOD_OBJ_CLASS, -EIO, "STATUS_DS_CANT_MOD_OBJ_CLASS"},
- {STATUS_DS_CROSS_DOM_MOVE_FAILED, -EIO,
- "STATUS_DS_CROSS_DOM_MOVE_FAILED"},
- {STATUS_DS_GC_NOT_AVAILABLE, -EIO, "STATUS_DS_GC_NOT_AVAILABLE"},
- {STATUS_DIRECTORY_SERVICE_REQUIRED, -EIO,
- "STATUS_DIRECTORY_SERVICE_REQUIRED"},
- {STATUS_REPARSE_ATTRIBUTE_CONFLICT, -EIO,
- "STATUS_REPARSE_ATTRIBUTE_CONFLICT"},
- {STATUS_CANT_ENABLE_DENY_ONLY, -EIO, "STATUS_CANT_ENABLE_DENY_ONLY"},
- {STATUS_FLOAT_MULTIPLE_FAULTS, -EIO, "STATUS_FLOAT_MULTIPLE_FAULTS"},
- {STATUS_FLOAT_MULTIPLE_TRAPS, -EIO, "STATUS_FLOAT_MULTIPLE_TRAPS"},
- {STATUS_DEVICE_REMOVED, -EIO, "STATUS_DEVICE_REMOVED"},
- {STATUS_JOURNAL_DELETE_IN_PROGRESS, -EIO,
- "STATUS_JOURNAL_DELETE_IN_PROGRESS"},
- {STATUS_JOURNAL_NOT_ACTIVE, -EIO, "STATUS_JOURNAL_NOT_ACTIVE"},
- {STATUS_NOINTERFACE, -EIO, "STATUS_NOINTERFACE"},
- {STATUS_DS_ADMIN_LIMIT_EXCEEDED, -EIO,
- "STATUS_DS_ADMIN_LIMIT_EXCEEDED"},
- {STATUS_DRIVER_FAILED_SLEEP, -EIO, "STATUS_DRIVER_FAILED_SLEEP"},
- {STATUS_MUTUAL_AUTHENTICATION_FAILED, -EIO,
- "STATUS_MUTUAL_AUTHENTICATION_FAILED"},
- {STATUS_CORRUPT_SYSTEM_FILE, -EIO, "STATUS_CORRUPT_SYSTEM_FILE"},
- {STATUS_DATATYPE_MISALIGNMENT_ERROR, -EIO,
- "STATUS_DATATYPE_MISALIGNMENT_ERROR"},
- {STATUS_WMI_READ_ONLY, -EROFS, "STATUS_WMI_READ_ONLY"},
- {STATUS_WMI_SET_FAILURE, -EIO, "STATUS_WMI_SET_FAILURE"},
- {STATUS_COMMITMENT_MINIMUM, -EIO, "STATUS_COMMITMENT_MINIMUM"},
- {STATUS_REG_NAT_CONSUMPTION, -EIO, "STATUS_REG_NAT_CONSUMPTION"},
- {STATUS_TRANSPORT_FULL, -EIO, "STATUS_TRANSPORT_FULL"},
- {STATUS_DS_SAM_INIT_FAILURE, -EIO, "STATUS_DS_SAM_INIT_FAILURE"},
- {STATUS_ONLY_IF_CONNECTED, -EIO, "STATUS_ONLY_IF_CONNECTED"},
- {STATUS_DS_SENSITIVE_GROUP_VIOLATION, -EIO,
- "STATUS_DS_SENSITIVE_GROUP_VIOLATION"},
- {STATUS_PNP_RESTART_ENUMERATION, -EIO,
- "STATUS_PNP_RESTART_ENUMERATION"},
- {STATUS_JOURNAL_ENTRY_DELETED, -EIO, "STATUS_JOURNAL_ENTRY_DELETED"},
- {STATUS_DS_CANT_MOD_PRIMARYGROUPID, -EIO,
- "STATUS_DS_CANT_MOD_PRIMARYGROUPID"},
- {STATUS_SYSTEM_IMAGE_BAD_SIGNATURE, -EIO,
- "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"},
- {STATUS_PNP_REBOOT_REQUIRED, -EIO, "STATUS_PNP_REBOOT_REQUIRED"},
- {STATUS_POWER_STATE_INVALID, -EIO, "STATUS_POWER_STATE_INVALID"},
- {STATUS_DS_INVALID_GROUP_TYPE, -EIO, "STATUS_DS_INVALID_GROUP_TYPE"},
- {STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, -EIO,
- "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"},
- {STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, -EIO,
- "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"},
- {STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, -EIO,
- "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"},
- {STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, -EIO,
- "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"},
- {STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, -EIO,
- "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"},
- {STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, -EIO,
- "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"},
- {STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, -EIO,
- "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"},
- {STATUS_DS_HAVE_PRIMARY_MEMBERS, -EIO,
- "STATUS_DS_HAVE_PRIMARY_MEMBERS"},
- {STATUS_WMI_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_WMI_NOT_SUPPORTED"},
- {STATUS_INSUFFICIENT_POWER, -EIO, "STATUS_INSUFFICIENT_POWER"},
- {STATUS_SAM_NEED_BOOTKEY_PASSWORD, -EIO,
- "STATUS_SAM_NEED_BOOTKEY_PASSWORD"},
- {STATUS_SAM_NEED_BOOTKEY_FLOPPY, -EIO,
- "STATUS_SAM_NEED_BOOTKEY_FLOPPY"},
- {STATUS_DS_CANT_START, -EIO, "STATUS_DS_CANT_START"},
- {STATUS_DS_INIT_FAILURE, -EIO, "STATUS_DS_INIT_FAILURE"},
- {STATUS_SAM_INIT_FAILURE, -EIO, "STATUS_SAM_INIT_FAILURE"},
- {STATUS_DS_GC_REQUIRED, -EIO, "STATUS_DS_GC_REQUIRED"},
- {STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, -EIO,
- "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"},
- {STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS, -EIO,
- "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"},
- {STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"},
- {STATUS_MULTIPLE_FAULT_VIOLATION, -EIO,
- "STATUS_MULTIPLE_FAULT_VIOLATION"},
- {STATUS_CURRENT_DOMAIN_NOT_ALLOWED, -EIO,
- "STATUS_CURRENT_DOMAIN_NOT_ALLOWED"},
- {STATUS_CANNOT_MAKE, -EIO, "STATUS_CANNOT_MAKE"},
- {STATUS_SYSTEM_SHUTDOWN, -EIO, "STATUS_SYSTEM_SHUTDOWN"},
- {STATUS_DS_INIT_FAILURE_CONSOLE, -EIO,
- "STATUS_DS_INIT_FAILURE_CONSOLE"},
- {STATUS_DS_SAM_INIT_FAILURE_CONSOLE, -EIO,
- "STATUS_DS_SAM_INIT_FAILURE_CONSOLE"},
- {STATUS_UNFINISHED_CONTEXT_DELETED, -EIO,
- "STATUS_UNFINISHED_CONTEXT_DELETED"},
- {STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"},
- /* Note that ENOATTTR and ENODATA are the same errno */
- {STATUS_OBJECTID_NOT_FOUND, -ENODATA, "STATUS_OBJECTID_NOT_FOUND"},
- {STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"},
- {STATUS_WRONG_CREDENTIAL_HANDLE, -EIO,
- "STATUS_WRONG_CREDENTIAL_HANDLE"},
- {STATUS_CRYPTO_SYSTEM_INVALID, -EIO, "STATUS_CRYPTO_SYSTEM_INVALID"},
- {STATUS_MAX_REFERRALS_EXCEEDED, -EIO, "STATUS_MAX_REFERRALS_EXCEEDED"},
- {STATUS_MUST_BE_KDC, -EIO, "STATUS_MUST_BE_KDC"},
- {STATUS_STRONG_CRYPTO_NOT_SUPPORTED, -EIO,
- "STATUS_STRONG_CRYPTO_NOT_SUPPORTED"},
- {STATUS_TOO_MANY_PRINCIPALS, -EIO, "STATUS_TOO_MANY_PRINCIPALS"},
- {STATUS_NO_PA_DATA, -EIO, "STATUS_NO_PA_DATA"},
- {STATUS_PKINIT_NAME_MISMATCH, -EIO, "STATUS_PKINIT_NAME_MISMATCH"},
- {STATUS_SMARTCARD_LOGON_REQUIRED, -EIO,
- "STATUS_SMARTCARD_LOGON_REQUIRED"},
- {STATUS_KDC_INVALID_REQUEST, -EIO, "STATUS_KDC_INVALID_REQUEST"},
- {STATUS_KDC_UNABLE_TO_REFER, -EIO, "STATUS_KDC_UNABLE_TO_REFER"},
- {STATUS_KDC_UNKNOWN_ETYPE, -EIO, "STATUS_KDC_UNKNOWN_ETYPE"},
- {STATUS_SHUTDOWN_IN_PROGRESS, -EIO, "STATUS_SHUTDOWN_IN_PROGRESS"},
- {STATUS_SERVER_SHUTDOWN_IN_PROGRESS, -EIO,
- "STATUS_SERVER_SHUTDOWN_IN_PROGRESS"},
- {STATUS_NOT_SUPPORTED_ON_SBS, -EOPNOTSUPP,
- "STATUS_NOT_SUPPORTED_ON_SBS"},
- {STATUS_WMI_GUID_DISCONNECTED, -EIO, "STATUS_WMI_GUID_DISCONNECTED"},
- {STATUS_WMI_ALREADY_DISABLED, -EIO, "STATUS_WMI_ALREADY_DISABLED"},
- {STATUS_WMI_ALREADY_ENABLED, -EIO, "STATUS_WMI_ALREADY_ENABLED"},
- {STATUS_MFT_TOO_FRAGMENTED, -EIO, "STATUS_MFT_TOO_FRAGMENTED"},
- {STATUS_COPY_PROTECTION_FAILURE, -EIO,
- "STATUS_COPY_PROTECTION_FAILURE"},
- {STATUS_CSS_AUTHENTICATION_FAILURE, -EIO,
- "STATUS_CSS_AUTHENTICATION_FAILURE"},
- {STATUS_CSS_KEY_NOT_PRESENT, -EIO, "STATUS_CSS_KEY_NOT_PRESENT"},
- {STATUS_CSS_KEY_NOT_ESTABLISHED, -EIO,
- "STATUS_CSS_KEY_NOT_ESTABLISHED"},
- {STATUS_CSS_SCRAMBLED_SECTOR, -EIO, "STATUS_CSS_SCRAMBLED_SECTOR"},
- {STATUS_CSS_REGION_MISMATCH, -EIO, "STATUS_CSS_REGION_MISMATCH"},
- {STATUS_CSS_RESETS_EXHAUSTED, -EIO, "STATUS_CSS_RESETS_EXHAUSTED"},
- {STATUS_PKINIT_FAILURE, -EIO, "STATUS_PKINIT_FAILURE"},
- {STATUS_SMARTCARD_SUBSYSTEM_FAILURE, -EIO,
- "STATUS_SMARTCARD_SUBSYSTEM_FAILURE"},
- {STATUS_NO_KERB_KEY, -EIO, "STATUS_NO_KERB_KEY"},
- {STATUS_HOST_DOWN, -EIO, "STATUS_HOST_DOWN"},
- {STATUS_UNSUPPORTED_PREAUTH, -EIO, "STATUS_UNSUPPORTED_PREAUTH"},
- {STATUS_EFS_ALG_BLOB_TOO_BIG, -EIO, "STATUS_EFS_ALG_BLOB_TOO_BIG"},
- {STATUS_PORT_NOT_SET, -EIO, "STATUS_PORT_NOT_SET"},
- {STATUS_DEBUGGER_INACTIVE, -EIO, "STATUS_DEBUGGER_INACTIVE"},
- {STATUS_DS_VERSION_CHECK_FAILURE, -EIO,
- "STATUS_DS_VERSION_CHECK_FAILURE"},
- {STATUS_AUDITING_DISABLED, -EIO, "STATUS_AUDITING_DISABLED"},
- {STATUS_PRENT4_MACHINE_ACCOUNT, -EIO, "STATUS_PRENT4_MACHINE_ACCOUNT"},
- {STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, -EIO,
- "STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER"},
- {STATUS_INVALID_IMAGE_WIN_32, -EIO, "STATUS_INVALID_IMAGE_WIN_32"},
- {STATUS_INVALID_IMAGE_WIN_64, -EIO, "STATUS_INVALID_IMAGE_WIN_64"},
- {STATUS_BAD_BINDINGS, -EIO, "STATUS_BAD_BINDINGS"},
- {STATUS_NETWORK_SESSION_EXPIRED, -EIO,
- "STATUS_NETWORK_SESSION_EXPIRED"},
- {STATUS_APPHELP_BLOCK, -EIO, "STATUS_APPHELP_BLOCK"},
- {STATUS_ALL_SIDS_FILTERED, -EIO, "STATUS_ALL_SIDS_FILTERED"},
- {STATUS_NOT_SAFE_MODE_DRIVER, -EIO, "STATUS_NOT_SAFE_MODE_DRIVER"},
- {STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT, -EACCES,
- "STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT"},
- {STATUS_ACCESS_DISABLED_BY_POLICY_PATH, -EACCES,
- "STATUS_ACCESS_DISABLED_BY_POLICY_PATH"},
- {STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER, -EACCES,
- "STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER"},
- {STATUS_ACCESS_DISABLED_BY_POLICY_OTHER, -EACCES,
- "STATUS_ACCESS_DISABLED_BY_POLICY_OTHER"},
- {STATUS_FAILED_DRIVER_ENTRY, -EIO, "STATUS_FAILED_DRIVER_ENTRY"},
- {STATUS_DEVICE_ENUMERATION_ERROR, -EIO,
- "STATUS_DEVICE_ENUMERATION_ERROR"},
- {STATUS_MOUNT_POINT_NOT_RESOLVED, -EIO,
- "STATUS_MOUNT_POINT_NOT_RESOLVED"},
- {STATUS_INVALID_DEVICE_OBJECT_PARAMETER, -EIO,
- "STATUS_INVALID_DEVICE_OBJECT_PARAMETER"},
- {STATUS_MCA_OCCURED, -EIO, "STATUS_MCA_OCCURED"},
- {STATUS_DRIVER_BLOCKED_CRITICAL, -EIO,
- "STATUS_DRIVER_BLOCKED_CRITICAL"},
- {STATUS_DRIVER_BLOCKED, -EIO, "STATUS_DRIVER_BLOCKED"},
- {STATUS_DRIVER_DATABASE_ERROR, -EIO, "STATUS_DRIVER_DATABASE_ERROR"},
- {STATUS_SYSTEM_HIVE_TOO_LARGE, -EIO, "STATUS_SYSTEM_HIVE_TOO_LARGE"},
- {STATUS_INVALID_IMPORT_OF_NON_DLL, -EIO,
- "STATUS_INVALID_IMPORT_OF_NON_DLL"},
- {STATUS_NO_SECRETS, -EIO, "STATUS_NO_SECRETS"},
- {STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, -EACCES,
- "STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY"},
- {STATUS_FAILED_STACK_SWITCH, -EIO, "STATUS_FAILED_STACK_SWITCH"},
- {STATUS_HEAP_CORRUPTION, -EIO, "STATUS_HEAP_CORRUPTION"},
- {STATUS_SMARTCARD_WRONG_PIN, -EIO, "STATUS_SMARTCARD_WRONG_PIN"},
- {STATUS_SMARTCARD_CARD_BLOCKED, -EIO, "STATUS_SMARTCARD_CARD_BLOCKED"},
- {STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED, -EIO,
- "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED"},
- {STATUS_SMARTCARD_NO_CARD, -EIO, "STATUS_SMARTCARD_NO_CARD"},
- {STATUS_SMARTCARD_NO_KEY_CONTAINER, -EIO,
- "STATUS_SMARTCARD_NO_KEY_CONTAINER"},
- {STATUS_SMARTCARD_NO_CERTIFICATE, -EIO,
- "STATUS_SMARTCARD_NO_CERTIFICATE"},
- {STATUS_SMARTCARD_NO_KEYSET, -EIO, "STATUS_SMARTCARD_NO_KEYSET"},
- {STATUS_SMARTCARD_IO_ERROR, -EIO, "STATUS_SMARTCARD_IO_ERROR"},
- {STATUS_DOWNGRADE_DETECTED, -EIO, "STATUS_DOWNGRADE_DETECTED"},
- {STATUS_SMARTCARD_CERT_REVOKED, -EIO, "STATUS_SMARTCARD_CERT_REVOKED"},
- {STATUS_ISSUING_CA_UNTRUSTED, -EIO, "STATUS_ISSUING_CA_UNTRUSTED"},
- {STATUS_REVOCATION_OFFLINE_C, -EIO, "STATUS_REVOCATION_OFFLINE_C"},
- {STATUS_PKINIT_CLIENT_FAILURE, -EIO, "STATUS_PKINIT_CLIENT_FAILURE"},
- {STATUS_SMARTCARD_CERT_EXPIRED, -EIO, "STATUS_SMARTCARD_CERT_EXPIRED"},
- {STATUS_DRIVER_FAILED_PRIOR_UNLOAD, -EIO,
- "STATUS_DRIVER_FAILED_PRIOR_UNLOAD"},
- {STATUS_SMARTCARD_SILENT_CONTEXT, -EIO,
- "STATUS_SMARTCARD_SILENT_CONTEXT"},
- {STATUS_PER_USER_TRUST_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_PER_USER_TRUST_QUOTA_EXCEEDED"},
- {STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED"},
- {STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED"},
- {STATUS_DS_NAME_NOT_UNIQUE, -EIO, "STATUS_DS_NAME_NOT_UNIQUE"},
- {STATUS_DS_DUPLICATE_ID_FOUND, -EIO, "STATUS_DS_DUPLICATE_ID_FOUND"},
- {STATUS_DS_GROUP_CONVERSION_ERROR, -EIO,
- "STATUS_DS_GROUP_CONVERSION_ERROR"},
- {STATUS_VOLSNAP_PREPARE_HIBERNATE, -EIO,
- "STATUS_VOLSNAP_PREPARE_HIBERNATE"},
- {STATUS_USER2USER_REQUIRED, -EIO, "STATUS_USER2USER_REQUIRED"},
- {STATUS_STACK_BUFFER_OVERRUN, -EIO, "STATUS_STACK_BUFFER_OVERRUN"},
- {STATUS_NO_S4U_PROT_SUPPORT, -EIO, "STATUS_NO_S4U_PROT_SUPPORT"},
- {STATUS_CROSSREALM_DELEGATION_FAILURE, -EIO,
- "STATUS_CROSSREALM_DELEGATION_FAILURE"},
- {STATUS_REVOCATION_OFFLINE_KDC, -EIO, "STATUS_REVOCATION_OFFLINE_KDC"},
- {STATUS_ISSUING_CA_UNTRUSTED_KDC, -EIO,
- "STATUS_ISSUING_CA_UNTRUSTED_KDC"},
- {STATUS_KDC_CERT_EXPIRED, -EIO, "STATUS_KDC_CERT_EXPIRED"},
- {STATUS_KDC_CERT_REVOKED, -EIO, "STATUS_KDC_CERT_REVOKED"},
- {STATUS_PARAMETER_QUOTA_EXCEEDED, -EDQUOT,
- "STATUS_PARAMETER_QUOTA_EXCEEDED"},
- {STATUS_HIBERNATION_FAILURE, -EIO, "STATUS_HIBERNATION_FAILURE"},
- {STATUS_DELAY_LOAD_FAILED, -EIO, "STATUS_DELAY_LOAD_FAILED"},
- {STATUS_AUTHENTICATION_FIREWALL_FAILED, -EIO,
- "STATUS_AUTHENTICATION_FIREWALL_FAILED"},
- {STATUS_VDM_DISALLOWED, -EIO, "STATUS_VDM_DISALLOWED"},
- {STATUS_HUNG_DISPLAY_DRIVER_THREAD, -EIO,
- "STATUS_HUNG_DISPLAY_DRIVER_THREAD"},
- {STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, -EIO,
- "STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE"},
- {STATUS_INVALID_CRUNTIME_PARAMETER, -EIO,
- "STATUS_INVALID_CRUNTIME_PARAMETER"},
- {STATUS_NTLM_BLOCKED, -EIO, "STATUS_NTLM_BLOCKED"},
- {STATUS_ASSERTION_FAILURE, -EIO, "STATUS_ASSERTION_FAILURE"},
- {STATUS_VERIFIER_STOP, -EIO, "STATUS_VERIFIER_STOP"},
- {STATUS_CALLBACK_POP_STACK, -EIO, "STATUS_CALLBACK_POP_STACK"},
- {STATUS_INCOMPATIBLE_DRIVER_BLOCKED, -EIO,
- "STATUS_INCOMPATIBLE_DRIVER_BLOCKED"},
- {STATUS_HIVE_UNLOADED, -EIO, "STATUS_HIVE_UNLOADED"},
- {STATUS_COMPRESSION_DISABLED, -EIO, "STATUS_COMPRESSION_DISABLED"},
- {STATUS_FILE_SYSTEM_LIMITATION, -EIO, "STATUS_FILE_SYSTEM_LIMITATION"},
- {STATUS_INVALID_IMAGE_HASH, -EIO, "STATUS_INVALID_IMAGE_HASH"},
- {STATUS_NOT_CAPABLE, -EIO, "STATUS_NOT_CAPABLE"},
- {STATUS_REQUEST_OUT_OF_SEQUENCE, -EIO,
- "STATUS_REQUEST_OUT_OF_SEQUENCE"},
- {STATUS_IMPLEMENTATION_LIMIT, -EIO, "STATUS_IMPLEMENTATION_LIMIT"},
- {STATUS_ELEVATION_REQUIRED, -EIO, "STATUS_ELEVATION_REQUIRED"},
- {STATUS_BEYOND_VDL, -EIO, "STATUS_BEYOND_VDL"},
- {STATUS_ENCOUNTERED_WRITE_IN_PROGRESS, -EIO,
- "STATUS_ENCOUNTERED_WRITE_IN_PROGRESS"},
- {STATUS_PTE_CHANGED, -EIO, "STATUS_PTE_CHANGED"},
- {STATUS_PURGE_FAILED, -EIO, "STATUS_PURGE_FAILED"},
- {STATUS_CRED_REQUIRES_CONFIRMATION, -EIO,
- "STATUS_CRED_REQUIRES_CONFIRMATION"},
- {STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, -EIO,
- "STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE"},
- {STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER, -EIO,
- "STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER"},
- {STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, -EIO,
- "STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE"},
- {STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, -EIO,
- "STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE"},
- {STATUS_CS_ENCRYPTION_FILE_NOT_CSE, -EIO,
- "STATUS_CS_ENCRYPTION_FILE_NOT_CSE"},
- {STATUS_INVALID_LABEL, -EIO, "STATUS_INVALID_LABEL"},
- {STATUS_DRIVER_PROCESS_TERMINATED, -EIO,
- "STATUS_DRIVER_PROCESS_TERMINATED"},
- {STATUS_AMBIGUOUS_SYSTEM_DEVICE, -EIO,
- "STATUS_AMBIGUOUS_SYSTEM_DEVICE"},
- {STATUS_SYSTEM_DEVICE_NOT_FOUND, -EIO,
- "STATUS_SYSTEM_DEVICE_NOT_FOUND"},
- {STATUS_RESTART_BOOT_APPLICATION, -EIO,
- "STATUS_RESTART_BOOT_APPLICATION"},
- {STATUS_INVALID_TASK_NAME, -EIO, "STATUS_INVALID_TASK_NAME"},
- {STATUS_INVALID_TASK_INDEX, -EIO, "STATUS_INVALID_TASK_INDEX"},
- {STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"},
- {STATUS_CALLBACK_BYPASS, -EIO, "STATUS_CALLBACK_BYPASS"},
- {STATUS_SERVER_UNAVAILABLE, -EAGAIN, "STATUS_SERVER_UNAVAILABLE"},
- {STATUS_FILE_NOT_AVAILABLE, -EAGAIN, "STATUS_FILE_NOT_AVAILABLE"},
- {STATUS_PORT_CLOSED, -EIO, "STATUS_PORT_CLOSED"},
- {STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"},
- {STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"},
- {STATUS_REQUEST_CANCELED, -EIO, "STATUS_REQUEST_CANCELED"},
- {STATUS_RECURSIVE_DISPATCH, -EIO, "STATUS_RECURSIVE_DISPATCH"},
- {STATUS_LPC_RECEIVE_BUFFER_EXPECTED, -EIO,
- "STATUS_LPC_RECEIVE_BUFFER_EXPECTED"},
- {STATUS_LPC_INVALID_CONNECTION_USAGE, -EIO,
- "STATUS_LPC_INVALID_CONNECTION_USAGE"},
- {STATUS_LPC_REQUESTS_NOT_ALLOWED, -EIO,
- "STATUS_LPC_REQUESTS_NOT_ALLOWED"},
- {STATUS_RESOURCE_IN_USE, -EIO, "STATUS_RESOURCE_IN_USE"},
- {STATUS_HARDWARE_MEMORY_ERROR, -EIO, "STATUS_HARDWARE_MEMORY_ERROR"},
- {STATUS_THREADPOOL_HANDLE_EXCEPTION, -EIO,
- "STATUS_THREADPOOL_HANDLE_EXCEPTION"},
- {STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED, -EIO,
- "STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED"},
- {STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED, -EIO,
- "STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED"},
- {STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED, -EIO,
- "STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED"},
- {STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED, -EIO,
- "STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED"},
- {STATUS_THREADPOOL_RELEASED_DURING_OPERATION, -EIO,
- "STATUS_THREADPOOL_RELEASED_DURING_OPERATION"},
- {STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING, -EIO,
- "STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING"},
- {STATUS_APC_RETURNED_WHILE_IMPERSONATING, -EIO,
- "STATUS_APC_RETURNED_WHILE_IMPERSONATING"},
- {STATUS_PROCESS_IS_PROTECTED, -EIO, "STATUS_PROCESS_IS_PROTECTED"},
- {STATUS_MCA_EXCEPTION, -EIO, "STATUS_MCA_EXCEPTION"},
- {STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE, -EIO,
- "STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE"},
- {STATUS_SYMLINK_CLASS_DISABLED, -EIO, "STATUS_SYMLINK_CLASS_DISABLED"},
- {STATUS_INVALID_IDN_NORMALIZATION, -EIO,
- "STATUS_INVALID_IDN_NORMALIZATION"},
- {STATUS_NO_UNICODE_TRANSLATION, -EIO, "STATUS_NO_UNICODE_TRANSLATION"},
- {STATUS_ALREADY_REGISTERED, -EIO, "STATUS_ALREADY_REGISTERED"},
- {STATUS_CONTEXT_MISMATCH, -EIO, "STATUS_CONTEXT_MISMATCH"},
- {STATUS_PORT_ALREADY_HAS_COMPLETION_LIST, -EIO,
- "STATUS_PORT_ALREADY_HAS_COMPLETION_LIST"},
- {STATUS_CALLBACK_RETURNED_THREAD_PRIORITY, -EIO,
- "STATUS_CALLBACK_RETURNED_THREAD_PRIORITY"},
- {STATUS_INVALID_THREAD, -EIO, "STATUS_INVALID_THREAD"},
- {STATUS_CALLBACK_RETURNED_TRANSACTION, -EIO,
- "STATUS_CALLBACK_RETURNED_TRANSACTION"},
- {STATUS_CALLBACK_RETURNED_LDR_LOCK, -EIO,
- "STATUS_CALLBACK_RETURNED_LDR_LOCK"},
- {STATUS_CALLBACK_RETURNED_LANG, -EIO, "STATUS_CALLBACK_RETURNED_LANG"},
- {STATUS_CALLBACK_RETURNED_PRI_BACK, -EIO,
- "STATUS_CALLBACK_RETURNED_PRI_BACK"},
- {STATUS_CALLBACK_RETURNED_THREAD_AFFINITY, -EIO,
- "STATUS_CALLBACK_RETURNED_THREAD_AFFINITY"},
- {STATUS_DISK_REPAIR_DISABLED, -EIO, "STATUS_DISK_REPAIR_DISABLED"},
- {STATUS_DS_DOMAIN_RENAME_IN_PROGRESS, -EIO,
- "STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"},
- {STATUS_DISK_QUOTA_EXCEEDED, -EDQUOT, "STATUS_DISK_QUOTA_EXCEEDED"},
- {STATUS_CONTENT_BLOCKED, -EIO, "STATUS_CONTENT_BLOCKED"},
- {STATUS_BAD_CLUSTERS, -EIO, "STATUS_BAD_CLUSTERS"},
- {STATUS_VOLUME_DIRTY, -EIO, "STATUS_VOLUME_DIRTY"},
- {STATUS_FILE_CHECKED_OUT, -EIO, "STATUS_FILE_CHECKED_OUT"},
- {STATUS_CHECKOUT_REQUIRED, -EIO, "STATUS_CHECKOUT_REQUIRED"},
- {STATUS_BAD_FILE_TYPE, -EIO, "STATUS_BAD_FILE_TYPE"},
- {STATUS_FILE_TOO_LARGE, -EIO, "STATUS_FILE_TOO_LARGE"},
- {STATUS_FORMS_AUTH_REQUIRED, -EIO, "STATUS_FORMS_AUTH_REQUIRED"},
- {STATUS_VIRUS_INFECTED, -EIO, "STATUS_VIRUS_INFECTED"},
- {STATUS_VIRUS_DELETED, -EIO, "STATUS_VIRUS_DELETED"},
- {STATUS_BAD_MCFG_TABLE, -EIO, "STATUS_BAD_MCFG_TABLE"},
- {STATUS_WOW_ASSERTION, -EIO, "STATUS_WOW_ASSERTION"},
- {STATUS_INVALID_SIGNATURE, -EIO, "STATUS_INVALID_SIGNATURE"},
- {STATUS_HMAC_NOT_SUPPORTED, -EIO, "STATUS_HMAC_NOT_SUPPORTED"},
- {STATUS_IPSEC_QUEUE_OVERFLOW, -EIO, "STATUS_IPSEC_QUEUE_OVERFLOW"},
- {STATUS_ND_QUEUE_OVERFLOW, -EIO, "STATUS_ND_QUEUE_OVERFLOW"},
- {STATUS_HOPLIMIT_EXCEEDED, -EIO, "STATUS_HOPLIMIT_EXCEEDED"},
- {STATUS_PROTOCOL_NOT_SUPPORTED, -EOPNOTSUPP,
- "STATUS_PROTOCOL_NOT_SUPPORTED"},
- {STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, -EIO,
- "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED"},
- {STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, -EIO,
- "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR"},
- {STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, -EIO,
- "STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR"},
- {STATUS_XML_PARSE_ERROR, -EIO, "STATUS_XML_PARSE_ERROR"},
- {STATUS_XMLDSIG_ERROR, -EIO, "STATUS_XMLDSIG_ERROR"},
- {STATUS_WRONG_COMPARTMENT, -EIO, "STATUS_WRONG_COMPARTMENT"},
- {STATUS_AUTHIP_FAILURE, -EIO, "STATUS_AUTHIP_FAILURE"},
- {DBG_NO_STATE_CHANGE, -EIO, "DBG_NO_STATE_CHANGE"},
- {DBG_APP_NOT_IDLE, -EIO, "DBG_APP_NOT_IDLE"},
- {RPC_NT_INVALID_STRING_BINDING, -EIO, "RPC_NT_INVALID_STRING_BINDING"},
- {RPC_NT_WRONG_KIND_OF_BINDING, -EIO, "RPC_NT_WRONG_KIND_OF_BINDING"},
- {RPC_NT_INVALID_BINDING, -EIO, "RPC_NT_INVALID_BINDING"},
- {RPC_NT_PROTSEQ_NOT_SUPPORTED, -EOPNOTSUPP,
- "RPC_NT_PROTSEQ_NOT_SUPPORTED"},
- {RPC_NT_INVALID_RPC_PROTSEQ, -EIO, "RPC_NT_INVALID_RPC_PROTSEQ"},
- {RPC_NT_INVALID_STRING_UUID, -EIO, "RPC_NT_INVALID_STRING_UUID"},
- {RPC_NT_INVALID_ENDPOINT_FORMAT, -EIO,
- "RPC_NT_INVALID_ENDPOINT_FORMAT"},
- {RPC_NT_INVALID_NET_ADDR, -EIO, "RPC_NT_INVALID_NET_ADDR"},
- {RPC_NT_NO_ENDPOINT_FOUND, -EIO, "RPC_NT_NO_ENDPOINT_FOUND"},
- {RPC_NT_INVALID_TIMEOUT, -EINVAL, "RPC_NT_INVALID_TIMEOUT"},
- {RPC_NT_OBJECT_NOT_FOUND, -ENOENT, "RPC_NT_OBJECT_NOT_FOUND"},
- {RPC_NT_ALREADY_REGISTERED, -EIO, "RPC_NT_ALREADY_REGISTERED"},
- {RPC_NT_TYPE_ALREADY_REGISTERED, -EIO,
- "RPC_NT_TYPE_ALREADY_REGISTERED"},
- {RPC_NT_ALREADY_LISTENING, -EIO, "RPC_NT_ALREADY_LISTENING"},
- {RPC_NT_NO_PROTSEQS_REGISTERED, -EIO, "RPC_NT_NO_PROTSEQS_REGISTERED"},
- {RPC_NT_NOT_LISTENING, -EIO, "RPC_NT_NOT_LISTENING"},
- {RPC_NT_UNKNOWN_MGR_TYPE, -EIO, "RPC_NT_UNKNOWN_MGR_TYPE"},
- {RPC_NT_UNKNOWN_IF, -EIO, "RPC_NT_UNKNOWN_IF"},
- {RPC_NT_NO_BINDINGS, -EIO, "RPC_NT_NO_BINDINGS"},
- {RPC_NT_NO_PROTSEQS, -EIO, "RPC_NT_NO_PROTSEQS"},
- {RPC_NT_CANT_CREATE_ENDPOINT, -EIO, "RPC_NT_CANT_CREATE_ENDPOINT"},
- {RPC_NT_OUT_OF_RESOURCES, -EIO, "RPC_NT_OUT_OF_RESOURCES"},
- {RPC_NT_SERVER_UNAVAILABLE, -EIO, "RPC_NT_SERVER_UNAVAILABLE"},
- {RPC_NT_SERVER_TOO_BUSY, -EBUSY, "RPC_NT_SERVER_TOO_BUSY"},
- {RPC_NT_INVALID_NETWORK_OPTIONS, -EIO,
- "RPC_NT_INVALID_NETWORK_OPTIONS"},
- {RPC_NT_NO_CALL_ACTIVE, -EIO, "RPC_NT_NO_CALL_ACTIVE"},
- {RPC_NT_CALL_FAILED, -EIO, "RPC_NT_CALL_FAILED"},
- {RPC_NT_CALL_FAILED_DNE, -EIO, "RPC_NT_CALL_FAILED_DNE"},
- {RPC_NT_PROTOCOL_ERROR, -EIO, "RPC_NT_PROTOCOL_ERROR"},
- {RPC_NT_UNSUPPORTED_TRANS_SYN, -EIO, "RPC_NT_UNSUPPORTED_TRANS_SYN"},
- {RPC_NT_UNSUPPORTED_TYPE, -EIO, "RPC_NT_UNSUPPORTED_TYPE"},
- {RPC_NT_INVALID_TAG, -EIO, "RPC_NT_INVALID_TAG"},
- {RPC_NT_INVALID_BOUND, -EIO, "RPC_NT_INVALID_BOUND"},
- {RPC_NT_NO_ENTRY_NAME, -EIO, "RPC_NT_NO_ENTRY_NAME"},
- {RPC_NT_INVALID_NAME_SYNTAX, -EIO, "RPC_NT_INVALID_NAME_SYNTAX"},
- {RPC_NT_UNSUPPORTED_NAME_SYNTAX, -EIO,
- "RPC_NT_UNSUPPORTED_NAME_SYNTAX"},
- {RPC_NT_UUID_NO_ADDRESS, -EIO, "RPC_NT_UUID_NO_ADDRESS"},
- {RPC_NT_DUPLICATE_ENDPOINT, -ENOTUNIQ, "RPC_NT_DUPLICATE_ENDPOINT"},
- {RPC_NT_UNKNOWN_AUTHN_TYPE, -EIO, "RPC_NT_UNKNOWN_AUTHN_TYPE"},
- {RPC_NT_MAX_CALLS_TOO_SMALL, -EIO, "RPC_NT_MAX_CALLS_TOO_SMALL"},
- {RPC_NT_STRING_TOO_LONG, -EIO, "RPC_NT_STRING_TOO_LONG"},
- {RPC_NT_PROTSEQ_NOT_FOUND, -EIO, "RPC_NT_PROTSEQ_NOT_FOUND"},
- {RPC_NT_PROCNUM_OUT_OF_RANGE, -EIO, "RPC_NT_PROCNUM_OUT_OF_RANGE"},
- {RPC_NT_BINDING_HAS_NO_AUTH, -EIO, "RPC_NT_BINDING_HAS_NO_AUTH"},
- {RPC_NT_UNKNOWN_AUTHN_SERVICE, -EIO, "RPC_NT_UNKNOWN_AUTHN_SERVICE"},
- {RPC_NT_UNKNOWN_AUTHN_LEVEL, -EIO, "RPC_NT_UNKNOWN_AUTHN_LEVEL"},
- {RPC_NT_INVALID_AUTH_IDENTITY, -EIO, "RPC_NT_INVALID_AUTH_IDENTITY"},
- {RPC_NT_UNKNOWN_AUTHZ_SERVICE, -EIO, "RPC_NT_UNKNOWN_AUTHZ_SERVICE"},
- {EPT_NT_INVALID_ENTRY, -EIO, "EPT_NT_INVALID_ENTRY"},
- {EPT_NT_CANT_PERFORM_OP, -EIO, "EPT_NT_CANT_PERFORM_OP"},
- {EPT_NT_NOT_REGISTERED, -EIO, "EPT_NT_NOT_REGISTERED"},
- {RPC_NT_NOTHING_TO_EXPORT, -EIO, "RPC_NT_NOTHING_TO_EXPORT"},
- {RPC_NT_INCOMPLETE_NAME, -EIO, "RPC_NT_INCOMPLETE_NAME"},
- {RPC_NT_INVALID_VERS_OPTION, -EIO, "RPC_NT_INVALID_VERS_OPTION"},
- {RPC_NT_NO_MORE_MEMBERS, -EIO, "RPC_NT_NO_MORE_MEMBERS"},
- {RPC_NT_NOT_ALL_OBJS_UNEXPORTED, -EIO,
- "RPC_NT_NOT_ALL_OBJS_UNEXPORTED"},
- {RPC_NT_INTERFACE_NOT_FOUND, -EIO, "RPC_NT_INTERFACE_NOT_FOUND"},
- {RPC_NT_ENTRY_ALREADY_EXISTS, -EIO, "RPC_NT_ENTRY_ALREADY_EXISTS"},
- {RPC_NT_ENTRY_NOT_FOUND, -EIO, "RPC_NT_ENTRY_NOT_FOUND"},
- {RPC_NT_NAME_SERVICE_UNAVAILABLE, -EIO,
- "RPC_NT_NAME_SERVICE_UNAVAILABLE"},
- {RPC_NT_INVALID_NAF_ID, -EIO, "RPC_NT_INVALID_NAF_ID"},
- {RPC_NT_CANNOT_SUPPORT, -EOPNOTSUPP, "RPC_NT_CANNOT_SUPPORT"},
- {RPC_NT_NO_CONTEXT_AVAILABLE, -EIO, "RPC_NT_NO_CONTEXT_AVAILABLE"},
- {RPC_NT_INTERNAL_ERROR, -EIO, "RPC_NT_INTERNAL_ERROR"},
- {RPC_NT_ZERO_DIVIDE, -EIO, "RPC_NT_ZERO_DIVIDE"},
- {RPC_NT_ADDRESS_ERROR, -EIO, "RPC_NT_ADDRESS_ERROR"},
- {RPC_NT_FP_DIV_ZERO, -EIO, "RPC_NT_FP_DIV_ZERO"},
- {RPC_NT_FP_UNDERFLOW, -EIO, "RPC_NT_FP_UNDERFLOW"},
- {RPC_NT_FP_OVERFLOW, -EIO, "RPC_NT_FP_OVERFLOW"},
- {RPC_NT_CALL_IN_PROGRESS, -EIO, "RPC_NT_CALL_IN_PROGRESS"},
- {RPC_NT_NO_MORE_BINDINGS, -EIO, "RPC_NT_NO_MORE_BINDINGS"},
- {RPC_NT_GROUP_MEMBER_NOT_FOUND, -EIO, "RPC_NT_GROUP_MEMBER_NOT_FOUND"},
- {EPT_NT_CANT_CREATE, -EIO, "EPT_NT_CANT_CREATE"},
- {RPC_NT_INVALID_OBJECT, -EIO, "RPC_NT_INVALID_OBJECT"},
- {RPC_NT_NO_INTERFACES, -EIO, "RPC_NT_NO_INTERFACES"},
- {RPC_NT_CALL_CANCELLED, -EIO, "RPC_NT_CALL_CANCELLED"},
- {RPC_NT_BINDING_INCOMPLETE, -EIO, "RPC_NT_BINDING_INCOMPLETE"},
- {RPC_NT_COMM_FAILURE, -EIO, "RPC_NT_COMM_FAILURE"},
- {RPC_NT_UNSUPPORTED_AUTHN_LEVEL, -EIO,
- "RPC_NT_UNSUPPORTED_AUTHN_LEVEL"},
- {RPC_NT_NO_PRINC_NAME, -EIO, "RPC_NT_NO_PRINC_NAME"},
- {RPC_NT_NOT_RPC_ERROR, -EIO, "RPC_NT_NOT_RPC_ERROR"},
- {RPC_NT_SEC_PKG_ERROR, -EIO, "RPC_NT_SEC_PKG_ERROR"},
- {RPC_NT_NOT_CANCELLED, -EIO, "RPC_NT_NOT_CANCELLED"},
- {RPC_NT_INVALID_ASYNC_HANDLE, -EIO, "RPC_NT_INVALID_ASYNC_HANDLE"},
- {RPC_NT_INVALID_ASYNC_CALL, -EIO, "RPC_NT_INVALID_ASYNC_CALL"},
- {RPC_NT_PROXY_ACCESS_DENIED, -EACCES, "RPC_NT_PROXY_ACCESS_DENIED"},
- {RPC_NT_NO_MORE_ENTRIES, -EIO, "RPC_NT_NO_MORE_ENTRIES"},
- {RPC_NT_SS_CHAR_TRANS_OPEN_FAIL, -EIO,
- "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"},
- {RPC_NT_SS_CHAR_TRANS_SHORT_FILE, -EIO,
- "RPC_NT_SS_CHAR_TRANS_SHORT_FILE"},
- {RPC_NT_SS_IN_NULL_CONTEXT, -EIO, "RPC_NT_SS_IN_NULL_CONTEXT"},
- {RPC_NT_SS_CONTEXT_MISMATCH, -EIO, "RPC_NT_SS_CONTEXT_MISMATCH"},
- {RPC_NT_SS_CONTEXT_DAMAGED, -EIO, "RPC_NT_SS_CONTEXT_DAMAGED"},
- {RPC_NT_SS_HANDLES_MISMATCH, -EIO, "RPC_NT_SS_HANDLES_MISMATCH"},
- {RPC_NT_SS_CANNOT_GET_CALL_HANDLE, -EIO,
- "RPC_NT_SS_CANNOT_GET_CALL_HANDLE"},
- {RPC_NT_NULL_REF_POINTER, -EIO, "RPC_NT_NULL_REF_POINTER"},
- {RPC_NT_ENUM_VALUE_OUT_OF_RANGE, -EIO,
- "RPC_NT_ENUM_VALUE_OUT_OF_RANGE"},
- {RPC_NT_BYTE_COUNT_TOO_SMALL, -EIO, "RPC_NT_BYTE_COUNT_TOO_SMALL"},
- {RPC_NT_BAD_STUB_DATA, -EIO, "RPC_NT_BAD_STUB_DATA"},
- {RPC_NT_INVALID_ES_ACTION, -EIO, "RPC_NT_INVALID_ES_ACTION"},
- {RPC_NT_WRONG_ES_VERSION, -EIO, "RPC_NT_WRONG_ES_VERSION"},
- {RPC_NT_WRONG_STUB_VERSION, -EIO, "RPC_NT_WRONG_STUB_VERSION"},
- {RPC_NT_INVALID_PIPE_OBJECT, -EIO, "RPC_NT_INVALID_PIPE_OBJECT"},
- {RPC_NT_INVALID_PIPE_OPERATION, -EIO, "RPC_NT_INVALID_PIPE_OPERATION"},
- {RPC_NT_WRONG_PIPE_VERSION, -EIO, "RPC_NT_WRONG_PIPE_VERSION"},
- {RPC_NT_PIPE_CLOSED, -EIO, "RPC_NT_PIPE_CLOSED"},
- {RPC_NT_PIPE_DISCIPLINE_ERROR, -EIO, "RPC_NT_PIPE_DISCIPLINE_ERROR"},
- {RPC_NT_PIPE_EMPTY, -EIO, "RPC_NT_PIPE_EMPTY"},
- {STATUS_PNP_BAD_MPS_TABLE, -EIO, "STATUS_PNP_BAD_MPS_TABLE"},
- {STATUS_PNP_TRANSLATION_FAILED, -EIO, "STATUS_PNP_TRANSLATION_FAILED"},
- {STATUS_PNP_IRQ_TRANSLATION_FAILED, -EIO,
- "STATUS_PNP_IRQ_TRANSLATION_FAILED"},
- {STATUS_PNP_INVALID_ID, -EIO, "STATUS_PNP_INVALID_ID"},
- {STATUS_IO_REISSUE_AS_CACHED, -EIO, "STATUS_IO_REISSUE_AS_CACHED"},
- {STATUS_CTX_WINSTATION_NAME_INVALID, -EIO,
- "STATUS_CTX_WINSTATION_NAME_INVALID"},
- {STATUS_CTX_INVALID_PD, -EIO, "STATUS_CTX_INVALID_PD"},
- {STATUS_CTX_PD_NOT_FOUND, -EIO, "STATUS_CTX_PD_NOT_FOUND"},
- {STATUS_CTX_CLOSE_PENDING, -EIO, "STATUS_CTX_CLOSE_PENDING"},
- {STATUS_CTX_NO_OUTBUF, -EIO, "STATUS_CTX_NO_OUTBUF"},
- {STATUS_CTX_MODEM_INF_NOT_FOUND, -EIO,
- "STATUS_CTX_MODEM_INF_NOT_FOUND"},
- {STATUS_CTX_INVALID_MODEMNAME, -EIO, "STATUS_CTX_INVALID_MODEMNAME"},
- {STATUS_CTX_RESPONSE_ERROR, -EIO, "STATUS_CTX_RESPONSE_ERROR"},
- {STATUS_CTX_MODEM_RESPONSE_TIMEOUT, -ETIMEDOUT,
- "STATUS_CTX_MODEM_RESPONSE_TIMEOUT"},
- {STATUS_CTX_MODEM_RESPONSE_NO_CARRIER, -EIO,
- "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"},
- {STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE, -EIO,
- "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE"},
- {STATUS_CTX_MODEM_RESPONSE_BUSY, -EBUSY,
- "STATUS_CTX_MODEM_RESPONSE_BUSY"},
- {STATUS_CTX_MODEM_RESPONSE_VOICE, -EIO,
- "STATUS_CTX_MODEM_RESPONSE_VOICE"},
- {STATUS_CTX_TD_ERROR, -EIO, "STATUS_CTX_TD_ERROR"},
- {STATUS_CTX_LICENSE_CLIENT_INVALID, -EIO,
- "STATUS_CTX_LICENSE_CLIENT_INVALID"},
- {STATUS_CTX_LICENSE_NOT_AVAILABLE, -EIO,
- "STATUS_CTX_LICENSE_NOT_AVAILABLE"},
- {STATUS_CTX_LICENSE_EXPIRED, -EIO, "STATUS_CTX_LICENSE_EXPIRED"},
- {STATUS_CTX_WINSTATION_NOT_FOUND, -EIO,
- "STATUS_CTX_WINSTATION_NOT_FOUND"},
- {STATUS_CTX_WINSTATION_NAME_COLLISION, -EIO,
- "STATUS_CTX_WINSTATION_NAME_COLLISION"},
- {STATUS_CTX_WINSTATION_BUSY, -EBUSY, "STATUS_CTX_WINSTATION_BUSY"},
- {STATUS_CTX_BAD_VIDEO_MODE, -EIO, "STATUS_CTX_BAD_VIDEO_MODE"},
- {STATUS_CTX_GRAPHICS_INVALID, -EIO, "STATUS_CTX_GRAPHICS_INVALID"},
- {STATUS_CTX_NOT_CONSOLE, -EIO, "STATUS_CTX_NOT_CONSOLE"},
- {STATUS_CTX_CLIENT_QUERY_TIMEOUT, -EIO,
- "STATUS_CTX_CLIENT_QUERY_TIMEOUT"},
- {STATUS_CTX_CONSOLE_DISCONNECT, -EIO, "STATUS_CTX_CONSOLE_DISCONNECT"},
- {STATUS_CTX_CONSOLE_CONNECT, -EIO, "STATUS_CTX_CONSOLE_CONNECT"},
- {STATUS_CTX_SHADOW_DENIED, -EIO, "STATUS_CTX_SHADOW_DENIED"},
- {STATUS_CTX_WINSTATION_ACCESS_DENIED, -EACCES,
- "STATUS_CTX_WINSTATION_ACCESS_DENIED"},
- {STATUS_CTX_INVALID_WD, -EIO, "STATUS_CTX_INVALID_WD"},
- {STATUS_CTX_WD_NOT_FOUND, -EIO, "STATUS_CTX_WD_NOT_FOUND"},
- {STATUS_CTX_SHADOW_INVALID, -EIO, "STATUS_CTX_SHADOW_INVALID"},
- {STATUS_CTX_SHADOW_DISABLED, -EIO, "STATUS_CTX_SHADOW_DISABLED"},
- {STATUS_RDP_PROTOCOL_ERROR, -EIO, "STATUS_RDP_PROTOCOL_ERROR"},
- {STATUS_CTX_CLIENT_LICENSE_NOT_SET, -EIO,
- "STATUS_CTX_CLIENT_LICENSE_NOT_SET"},
- {STATUS_CTX_CLIENT_LICENSE_IN_USE, -EIO,
- "STATUS_CTX_CLIENT_LICENSE_IN_USE"},
- {STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE, -EIO,
- "STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE"},
- {STATUS_CTX_SHADOW_NOT_RUNNING, -EIO, "STATUS_CTX_SHADOW_NOT_RUNNING"},
- {STATUS_CTX_LOGON_DISABLED, -EIO, "STATUS_CTX_LOGON_DISABLED"},
- {STATUS_CTX_SECURITY_LAYER_ERROR, -EIO,
- "STATUS_CTX_SECURITY_LAYER_ERROR"},
- {STATUS_TS_INCOMPATIBLE_SESSIONS, -EIO,
- "STATUS_TS_INCOMPATIBLE_SESSIONS"},
- {STATUS_MUI_FILE_NOT_FOUND, -EIO, "STATUS_MUI_FILE_NOT_FOUND"},
- {STATUS_MUI_INVALID_FILE, -EIO, "STATUS_MUI_INVALID_FILE"},
- {STATUS_MUI_INVALID_RC_CONFIG, -EIO, "STATUS_MUI_INVALID_RC_CONFIG"},
- {STATUS_MUI_INVALID_LOCALE_NAME, -EIO,
- "STATUS_MUI_INVALID_LOCALE_NAME"},
- {STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME, -EIO,
- "STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME"},
- {STATUS_MUI_FILE_NOT_LOADED, -EIO, "STATUS_MUI_FILE_NOT_LOADED"},
- {STATUS_RESOURCE_ENUM_USER_STOP, -EIO,
- "STATUS_RESOURCE_ENUM_USER_STOP"},
- {STATUS_CLUSTER_INVALID_NODE, -EIO, "STATUS_CLUSTER_INVALID_NODE"},
- {STATUS_CLUSTER_NODE_EXISTS, -EIO, "STATUS_CLUSTER_NODE_EXISTS"},
- {STATUS_CLUSTER_JOIN_IN_PROGRESS, -EIO,
- "STATUS_CLUSTER_JOIN_IN_PROGRESS"},
- {STATUS_CLUSTER_NODE_NOT_FOUND, -EIO, "STATUS_CLUSTER_NODE_NOT_FOUND"},
- {STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND, -EIO,
- "STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND"},
- {STATUS_CLUSTER_NETWORK_EXISTS, -EIO, "STATUS_CLUSTER_NETWORK_EXISTS"},
- {STATUS_CLUSTER_NETWORK_NOT_FOUND, -EIO,
- "STATUS_CLUSTER_NETWORK_NOT_FOUND"},
- {STATUS_CLUSTER_NETINTERFACE_EXISTS, -EIO,
- "STATUS_CLUSTER_NETINTERFACE_EXISTS"},
- {STATUS_CLUSTER_NETINTERFACE_NOT_FOUND, -EIO,
- "STATUS_CLUSTER_NETINTERFACE_NOT_FOUND"},
- {STATUS_CLUSTER_INVALID_REQUEST, -EIO,
- "STATUS_CLUSTER_INVALID_REQUEST"},
- {STATUS_CLUSTER_INVALID_NETWORK_PROVIDER, -EIO,
- "STATUS_CLUSTER_INVALID_NETWORK_PROVIDER"},
- {STATUS_CLUSTER_NODE_DOWN, -EIO, "STATUS_CLUSTER_NODE_DOWN"},
- {STATUS_CLUSTER_NODE_UNREACHABLE, -EIO,
- "STATUS_CLUSTER_NODE_UNREACHABLE"},
- {STATUS_CLUSTER_NODE_NOT_MEMBER, -EIO,
- "STATUS_CLUSTER_NODE_NOT_MEMBER"},
- {STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS, -EIO,
- "STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS"},
- {STATUS_CLUSTER_INVALID_NETWORK, -EIO,
- "STATUS_CLUSTER_INVALID_NETWORK"},
- {STATUS_CLUSTER_NO_NET_ADAPTERS, -EIO,
- "STATUS_CLUSTER_NO_NET_ADAPTERS"},
- {STATUS_CLUSTER_NODE_UP, -EIO, "STATUS_CLUSTER_NODE_UP"},
- {STATUS_CLUSTER_NODE_PAUSED, -EIO, "STATUS_CLUSTER_NODE_PAUSED"},
- {STATUS_CLUSTER_NODE_NOT_PAUSED, -EIO,
- "STATUS_CLUSTER_NODE_NOT_PAUSED"},
- {STATUS_CLUSTER_NO_SECURITY_CONTEXT, -EIO,
- "STATUS_CLUSTER_NO_SECURITY_CONTEXT"},
- {STATUS_CLUSTER_NETWORK_NOT_INTERNAL, -EIO,
- "STATUS_CLUSTER_NETWORK_NOT_INTERNAL"},
- {STATUS_CLUSTER_POISONED, -EIO, "STATUS_CLUSTER_POISONED"},
- {STATUS_ACPI_INVALID_OPCODE, -EIO, "STATUS_ACPI_INVALID_OPCODE"},
- {STATUS_ACPI_STACK_OVERFLOW, -EIO, "STATUS_ACPI_STACK_OVERFLOW"},
- {STATUS_ACPI_ASSERT_FAILED, -EIO, "STATUS_ACPI_ASSERT_FAILED"},
- {STATUS_ACPI_INVALID_INDEX, -EIO, "STATUS_ACPI_INVALID_INDEX"},
- {STATUS_ACPI_INVALID_ARGUMENT, -EIO, "STATUS_ACPI_INVALID_ARGUMENT"},
- {STATUS_ACPI_FATAL, -EIO, "STATUS_ACPI_FATAL"},
- {STATUS_ACPI_INVALID_SUPERNAME, -EIO, "STATUS_ACPI_INVALID_SUPERNAME"},
- {STATUS_ACPI_INVALID_ARGTYPE, -EIO, "STATUS_ACPI_INVALID_ARGTYPE"},
- {STATUS_ACPI_INVALID_OBJTYPE, -EIO, "STATUS_ACPI_INVALID_OBJTYPE"},
- {STATUS_ACPI_INVALID_TARGETTYPE, -EIO,
- "STATUS_ACPI_INVALID_TARGETTYPE"},
- {STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, -EIO,
- "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"},
- {STATUS_ACPI_ADDRESS_NOT_MAPPED, -EIO,
- "STATUS_ACPI_ADDRESS_NOT_MAPPED"},
- {STATUS_ACPI_INVALID_EVENTTYPE, -EIO, "STATUS_ACPI_INVALID_EVENTTYPE"},
- {STATUS_ACPI_HANDLER_COLLISION, -EIO, "STATUS_ACPI_HANDLER_COLLISION"},
- {STATUS_ACPI_INVALID_DATA, -EIO, "STATUS_ACPI_INVALID_DATA"},
- {STATUS_ACPI_INVALID_REGION, -EIO, "STATUS_ACPI_INVALID_REGION"},
- {STATUS_ACPI_INVALID_ACCESS_SIZE, -EIO,
- "STATUS_ACPI_INVALID_ACCESS_SIZE"},
- {STATUS_ACPI_ACQUIRE_GLOBAL_LOCK, -EIO,
- "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"},
- {STATUS_ACPI_ALREADY_INITIALIZED, -EIO,
- "STATUS_ACPI_ALREADY_INITIALIZED"},
- {STATUS_ACPI_NOT_INITIALIZED, -EIO, "STATUS_ACPI_NOT_INITIALIZED"},
- {STATUS_ACPI_INVALID_MUTEX_LEVEL, -EIO,
- "STATUS_ACPI_INVALID_MUTEX_LEVEL"},
- {STATUS_ACPI_MUTEX_NOT_OWNED, -EIO, "STATUS_ACPI_MUTEX_NOT_OWNED"},
- {STATUS_ACPI_MUTEX_NOT_OWNER, -EIO, "STATUS_ACPI_MUTEX_NOT_OWNER"},
- {STATUS_ACPI_RS_ACCESS, -EIO, "STATUS_ACPI_RS_ACCESS"},
- {STATUS_ACPI_INVALID_TABLE, -EIO, "STATUS_ACPI_INVALID_TABLE"},
- {STATUS_ACPI_REG_HANDLER_FAILED, -EIO,
- "STATUS_ACPI_REG_HANDLER_FAILED"},
- {STATUS_ACPI_POWER_REQUEST_FAILED, -EIO,
- "STATUS_ACPI_POWER_REQUEST_FAILED"},
- {STATUS_SXS_SECTION_NOT_FOUND, -EIO, "STATUS_SXS_SECTION_NOT_FOUND"},
- {STATUS_SXS_CANT_GEN_ACTCTX, -EIO, "STATUS_SXS_CANT_GEN_ACTCTX"},
- {STATUS_SXS_INVALID_ACTCTXDATA_FORMAT, -EIO,
- "STATUS_SXS_INVALID_ACTCTXDATA_FORMAT"},
- {STATUS_SXS_ASSEMBLY_NOT_FOUND, -EIO, "STATUS_SXS_ASSEMBLY_NOT_FOUND"},
- {STATUS_SXS_MANIFEST_FORMAT_ERROR, -EIO,
- "STATUS_SXS_MANIFEST_FORMAT_ERROR"},
- {STATUS_SXS_MANIFEST_PARSE_ERROR, -EIO,
- "STATUS_SXS_MANIFEST_PARSE_ERROR"},
- {STATUS_SXS_ACTIVATION_CONTEXT_DISABLED, -EIO,
- "STATUS_SXS_ACTIVATION_CONTEXT_DISABLED"},
- {STATUS_SXS_KEY_NOT_FOUND, -EIO, "STATUS_SXS_KEY_NOT_FOUND"},
- {STATUS_SXS_VERSION_CONFLICT, -EIO, "STATUS_SXS_VERSION_CONFLICT"},
- {STATUS_SXS_WRONG_SECTION_TYPE, -EIO, "STATUS_SXS_WRONG_SECTION_TYPE"},
- {STATUS_SXS_THREAD_QUERIES_DISABLED, -EIO,
- "STATUS_SXS_THREAD_QUERIES_DISABLED"},
- {STATUS_SXS_ASSEMBLY_MISSING, -EIO, "STATUS_SXS_ASSEMBLY_MISSING"},
- {STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET, -EIO,
- "STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET"},
- {STATUS_SXS_EARLY_DEACTIVATION, -EIO, "STATUS_SXS_EARLY_DEACTIVATION"},
- {STATUS_SXS_INVALID_DEACTIVATION, -EIO,
- "STATUS_SXS_INVALID_DEACTIVATION"},
- {STATUS_SXS_MULTIPLE_DEACTIVATION, -EIO,
- "STATUS_SXS_MULTIPLE_DEACTIVATION"},
- {STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, -EIO,
- "STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY"},
- {STATUS_SXS_PROCESS_TERMINATION_REQUESTED, -EIO,
- "STATUS_SXS_PROCESS_TERMINATION_REQUESTED"},
- {STATUS_SXS_CORRUPT_ACTIVATION_STACK, -EIO,
- "STATUS_SXS_CORRUPT_ACTIVATION_STACK"},
- {STATUS_SXS_CORRUPTION, -EIO, "STATUS_SXS_CORRUPTION"},
- {STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, -EIO,
- "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE"},
- {STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, -EIO,
- "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME"},
- {STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, -EIO,
- "STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE"},
- {STATUS_SXS_IDENTITY_PARSE_ERROR, -EIO,
- "STATUS_SXS_IDENTITY_PARSE_ERROR"},
- {STATUS_SXS_COMPONENT_STORE_CORRUPT, -EIO,
- "STATUS_SXS_COMPONENT_STORE_CORRUPT"},
- {STATUS_SXS_FILE_HASH_MISMATCH, -EIO, "STATUS_SXS_FILE_HASH_MISMATCH"},
- {STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, -EIO,
- "STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT"},
- {STATUS_SXS_IDENTITIES_DIFFERENT, -EIO,
- "STATUS_SXS_IDENTITIES_DIFFERENT"},
- {STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, -EIO,
- "STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT"},
- {STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY, -EIO,
- "STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY"},
- {STATUS_ADVANCED_INSTALLER_FAILED, -EIO,
- "STATUS_ADVANCED_INSTALLER_FAILED"},
- {STATUS_XML_ENCODING_MISMATCH, -EIO, "STATUS_XML_ENCODING_MISMATCH"},
- {STATUS_SXS_MANIFEST_TOO_BIG, -EIO, "STATUS_SXS_MANIFEST_TOO_BIG"},
- {STATUS_SXS_SETTING_NOT_REGISTERED, -EIO,
- "STATUS_SXS_SETTING_NOT_REGISTERED"},
- {STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE, -EIO,
- "STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE"},
- {STATUS_SMI_PRIMITIVE_INSTALLER_FAILED, -EIO,
- "STATUS_SMI_PRIMITIVE_INSTALLER_FAILED"},
- {STATUS_GENERIC_COMMAND_FAILED, -EIO, "STATUS_GENERIC_COMMAND_FAILED"},
- {STATUS_SXS_FILE_HASH_MISSING, -EIO, "STATUS_SXS_FILE_HASH_MISSING"},
- {STATUS_TRANSACTIONAL_CONFLICT, -EIO, "STATUS_TRANSACTIONAL_CONFLICT"},
- {STATUS_INVALID_TRANSACTION, -EIO, "STATUS_INVALID_TRANSACTION"},
- {STATUS_TRANSACTION_NOT_ACTIVE, -EIO, "STATUS_TRANSACTION_NOT_ACTIVE"},
- {STATUS_TM_INITIALIZATION_FAILED, -EIO,
- "STATUS_TM_INITIALIZATION_FAILED"},
- {STATUS_RM_NOT_ACTIVE, -EIO, "STATUS_RM_NOT_ACTIVE"},
- {STATUS_RM_METADATA_CORRUPT, -EIO, "STATUS_RM_METADATA_CORRUPT"},
- {STATUS_TRANSACTION_NOT_JOINED, -EIO, "STATUS_TRANSACTION_NOT_JOINED"},
- {STATUS_DIRECTORY_NOT_RM, -EIO, "STATUS_DIRECTORY_NOT_RM"},
- {STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE, -EIO,
- "STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE"},
- {STATUS_LOG_RESIZE_INVALID_SIZE, -EIO,
- "STATUS_LOG_RESIZE_INVALID_SIZE"},
- {STATUS_REMOTE_FILE_VERSION_MISMATCH, -EIO,
- "STATUS_REMOTE_FILE_VERSION_MISMATCH"},
- {STATUS_CRM_PROTOCOL_ALREADY_EXISTS, -EIO,
- "STATUS_CRM_PROTOCOL_ALREADY_EXISTS"},
- {STATUS_TRANSACTION_PROPAGATION_FAILED, -EIO,
- "STATUS_TRANSACTION_PROPAGATION_FAILED"},
- {STATUS_CRM_PROTOCOL_NOT_FOUND, -EIO, "STATUS_CRM_PROTOCOL_NOT_FOUND"},
- {STATUS_TRANSACTION_SUPERIOR_EXISTS, -EIO,
- "STATUS_TRANSACTION_SUPERIOR_EXISTS"},
- {STATUS_TRANSACTION_REQUEST_NOT_VALID, -EIO,
- "STATUS_TRANSACTION_REQUEST_NOT_VALID"},
- {STATUS_TRANSACTION_NOT_REQUESTED, -EIO,
- "STATUS_TRANSACTION_NOT_REQUESTED"},
- {STATUS_TRANSACTION_ALREADY_ABORTED, -EIO,
- "STATUS_TRANSACTION_ALREADY_ABORTED"},
- {STATUS_TRANSACTION_ALREADY_COMMITTED, -EIO,
- "STATUS_TRANSACTION_ALREADY_COMMITTED"},
- {STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER, -EIO,
- "STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER"},
- {STATUS_CURRENT_TRANSACTION_NOT_VALID, -EIO,
- "STATUS_CURRENT_TRANSACTION_NOT_VALID"},
- {STATUS_LOG_GROWTH_FAILED, -EIO, "STATUS_LOG_GROWTH_FAILED"},
- {STATUS_OBJECT_NO_LONGER_EXISTS, -EIO,
- "STATUS_OBJECT_NO_LONGER_EXISTS"},
- {STATUS_STREAM_MINIVERSION_NOT_FOUND, -EIO,
- "STATUS_STREAM_MINIVERSION_NOT_FOUND"},
- {STATUS_STREAM_MINIVERSION_NOT_VALID, -EIO,
- "STATUS_STREAM_MINIVERSION_NOT_VALID"},
- {STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, -EIO,
- "STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION"},
- {STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, -EIO,
- "STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT"},
- {STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS, -EIO,
- "STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS"},
- {STATUS_HANDLE_NO_LONGER_VALID, -EIO, "STATUS_HANDLE_NO_LONGER_VALID"},
- {STATUS_LOG_CORRUPTION_DETECTED, -EIO,
- "STATUS_LOG_CORRUPTION_DETECTED"},
- {STATUS_RM_DISCONNECTED, -EIO, "STATUS_RM_DISCONNECTED"},
- {STATUS_ENLISTMENT_NOT_SUPERIOR, -EIO,
- "STATUS_ENLISTMENT_NOT_SUPERIOR"},
- {STATUS_FILE_IDENTITY_NOT_PERSISTENT, -EIO,
- "STATUS_FILE_IDENTITY_NOT_PERSISTENT"},
- {STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, -EIO,
- "STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY"},
- {STATUS_CANT_CROSS_RM_BOUNDARY, -EIO, "STATUS_CANT_CROSS_RM_BOUNDARY"},
- {STATUS_TXF_DIR_NOT_EMPTY, -EIO, "STATUS_TXF_DIR_NOT_EMPTY"},
- {STATUS_INDOUBT_TRANSACTIONS_EXIST, -EIO,
- "STATUS_INDOUBT_TRANSACTIONS_EXIST"},
- {STATUS_TM_VOLATILE, -EIO, "STATUS_TM_VOLATILE"},
- {STATUS_ROLLBACK_TIMER_EXPIRED, -EIO, "STATUS_ROLLBACK_TIMER_EXPIRED"},
- {STATUS_TXF_ATTRIBUTE_CORRUPT, -EIO, "STATUS_TXF_ATTRIBUTE_CORRUPT"},
- {STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION, -EIO,
- "STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION"},
- {STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED, -EIO,
- "STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED"},
- {STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, -EIO,
- "STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE"},
- {STATUS_TRANSACTION_REQUIRED_PROMOTION, -EIO,
- "STATUS_TRANSACTION_REQUIRED_PROMOTION"},
- {STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION, -EIO,
- "STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION"},
- {STATUS_TRANSACTIONS_NOT_FROZEN, -EIO,
- "STATUS_TRANSACTIONS_NOT_FROZEN"},
- {STATUS_TRANSACTION_FREEZE_IN_PROGRESS, -EIO,
- "STATUS_TRANSACTION_FREEZE_IN_PROGRESS"},
- {STATUS_NOT_SNAPSHOT_VOLUME, -EIO, "STATUS_NOT_SNAPSHOT_VOLUME"},
- {STATUS_NO_SAVEPOINT_WITH_OPEN_FILES, -EIO,
- "STATUS_NO_SAVEPOINT_WITH_OPEN_FILES"},
- {STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION, -EIO,
- "STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION"},
- {STATUS_TM_IDENTITY_MISMATCH, -EIO, "STATUS_TM_IDENTITY_MISMATCH"},
- {STATUS_FLOATED_SECTION, -EIO, "STATUS_FLOATED_SECTION"},
- {STATUS_CANNOT_ACCEPT_TRANSACTED_WORK, -EIO,
- "STATUS_CANNOT_ACCEPT_TRANSACTED_WORK"},
- {STATUS_CANNOT_ABORT_TRANSACTIONS, -EIO,
- "STATUS_CANNOT_ABORT_TRANSACTIONS"},
- {STATUS_TRANSACTION_NOT_FOUND, -EIO, "STATUS_TRANSACTION_NOT_FOUND"},
- {STATUS_RESOURCEMANAGER_NOT_FOUND, -EIO,
- "STATUS_RESOURCEMANAGER_NOT_FOUND"},
- {STATUS_ENLISTMENT_NOT_FOUND, -EIO, "STATUS_ENLISTMENT_NOT_FOUND"},
- {STATUS_TRANSACTIONMANAGER_NOT_FOUND, -EIO,
- "STATUS_TRANSACTIONMANAGER_NOT_FOUND"},
- {STATUS_TRANSACTIONMANAGER_NOT_ONLINE, -EIO,
- "STATUS_TRANSACTIONMANAGER_NOT_ONLINE"},
- {STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, -EIO,
- "STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION"},
- {STATUS_TRANSACTION_NOT_ROOT, -EIO, "STATUS_TRANSACTION_NOT_ROOT"},
- {STATUS_TRANSACTION_OBJECT_EXPIRED, -EIO,
- "STATUS_TRANSACTION_OBJECT_EXPIRED"},
- {STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, -EIO,
- "STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION"},
- {STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED, -EIO,
- "STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED"},
- {STATUS_TRANSACTION_RECORD_TOO_LONG, -EIO,
- "STATUS_TRANSACTION_RECORD_TOO_LONG"},
- {STATUS_NO_LINK_TRACKING_IN_TRANSACTION, -EIO,
- "STATUS_NO_LINK_TRACKING_IN_TRANSACTION"},
- {STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, -EOPNOTSUPP,
- "STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION"},
- {STATUS_TRANSACTION_INTEGRITY_VIOLATED, -EIO,
- "STATUS_TRANSACTION_INTEGRITY_VIOLATED"},
- {STATUS_LOG_SECTOR_INVALID, -EIO, "STATUS_LOG_SECTOR_INVALID"},
- {STATUS_LOG_SECTOR_PARITY_INVALID, -EIO,
- "STATUS_LOG_SECTOR_PARITY_INVALID"},
- {STATUS_LOG_SECTOR_REMAPPED, -EIO, "STATUS_LOG_SECTOR_REMAPPED"},
- {STATUS_LOG_BLOCK_INCOMPLETE, -EIO, "STATUS_LOG_BLOCK_INCOMPLETE"},
- {STATUS_LOG_INVALID_RANGE, -EIO, "STATUS_LOG_INVALID_RANGE"},
- {STATUS_LOG_BLOCKS_EXHAUSTED, -EIO, "STATUS_LOG_BLOCKS_EXHAUSTED"},
- {STATUS_LOG_READ_CONTEXT_INVALID, -EIO,
- "STATUS_LOG_READ_CONTEXT_INVALID"},
- {STATUS_LOG_RESTART_INVALID, -EIO, "STATUS_LOG_RESTART_INVALID"},
- {STATUS_LOG_BLOCK_VERSION, -EIO, "STATUS_LOG_BLOCK_VERSION"},
- {STATUS_LOG_BLOCK_INVALID, -EIO, "STATUS_LOG_BLOCK_INVALID"},
- {STATUS_LOG_READ_MODE_INVALID, -EIO, "STATUS_LOG_READ_MODE_INVALID"},
- {STATUS_LOG_METADATA_CORRUPT, -EIO, "STATUS_LOG_METADATA_CORRUPT"},
- {STATUS_LOG_METADATA_INVALID, -EIO, "STATUS_LOG_METADATA_INVALID"},
- {STATUS_LOG_METADATA_INCONSISTENT, -EIO,
- "STATUS_LOG_METADATA_INCONSISTENT"},
- {STATUS_LOG_RESERVATION_INVALID, -EIO,
- "STATUS_LOG_RESERVATION_INVALID"},
- {STATUS_LOG_CANT_DELETE, -EIO, "STATUS_LOG_CANT_DELETE"},
- {STATUS_LOG_CONTAINER_LIMIT_EXCEEDED, -EIO,
- "STATUS_LOG_CONTAINER_LIMIT_EXCEEDED"},
- {STATUS_LOG_START_OF_LOG, -EIO, "STATUS_LOG_START_OF_LOG"},
- {STATUS_LOG_POLICY_ALREADY_INSTALLED, -EIO,
- "STATUS_LOG_POLICY_ALREADY_INSTALLED"},
- {STATUS_LOG_POLICY_NOT_INSTALLED, -EIO,
- "STATUS_LOG_POLICY_NOT_INSTALLED"},
- {STATUS_LOG_POLICY_INVALID, -EIO, "STATUS_LOG_POLICY_INVALID"},
- {STATUS_LOG_POLICY_CONFLICT, -EIO, "STATUS_LOG_POLICY_CONFLICT"},
- {STATUS_LOG_PINNED_ARCHIVE_TAIL, -EIO,
- "STATUS_LOG_PINNED_ARCHIVE_TAIL"},
- {STATUS_LOG_RECORD_NONEXISTENT, -EIO, "STATUS_LOG_RECORD_NONEXISTENT"},
- {STATUS_LOG_RECORDS_RESERVED_INVALID, -EIO,
- "STATUS_LOG_RECORDS_RESERVED_INVALID"},
- {STATUS_LOG_SPACE_RESERVED_INVALID, -EIO,
- "STATUS_LOG_SPACE_RESERVED_INVALID"},
- {STATUS_LOG_TAIL_INVALID, -EIO, "STATUS_LOG_TAIL_INVALID"},
- {STATUS_LOG_FULL, -EIO, "STATUS_LOG_FULL"},
- {STATUS_LOG_MULTIPLEXED, -EIO, "STATUS_LOG_MULTIPLEXED"},
- {STATUS_LOG_DEDICATED, -EIO, "STATUS_LOG_DEDICATED"},
- {STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS, -EIO,
- "STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS"},
- {STATUS_LOG_ARCHIVE_IN_PROGRESS, -EIO,
- "STATUS_LOG_ARCHIVE_IN_PROGRESS"},
- {STATUS_LOG_EPHEMERAL, -EIO, "STATUS_LOG_EPHEMERAL"},
- {STATUS_LOG_NOT_ENOUGH_CONTAINERS, -EIO,
- "STATUS_LOG_NOT_ENOUGH_CONTAINERS"},
- {STATUS_LOG_CLIENT_ALREADY_REGISTERED, -EIO,
- "STATUS_LOG_CLIENT_ALREADY_REGISTERED"},
- {STATUS_LOG_CLIENT_NOT_REGISTERED, -EIO,
- "STATUS_LOG_CLIENT_NOT_REGISTERED"},
- {STATUS_LOG_FULL_HANDLER_IN_PROGRESS, -EIO,
- "STATUS_LOG_FULL_HANDLER_IN_PROGRESS"},
- {STATUS_LOG_CONTAINER_READ_FAILED, -EIO,
- "STATUS_LOG_CONTAINER_READ_FAILED"},
- {STATUS_LOG_CONTAINER_WRITE_FAILED, -EIO,
- "STATUS_LOG_CONTAINER_WRITE_FAILED"},
- {STATUS_LOG_CONTAINER_OPEN_FAILED, -EIO,
- "STATUS_LOG_CONTAINER_OPEN_FAILED"},
- {STATUS_LOG_CONTAINER_STATE_INVALID, -EIO,
- "STATUS_LOG_CONTAINER_STATE_INVALID"},
- {STATUS_LOG_STATE_INVALID, -EIO, "STATUS_LOG_STATE_INVALID"},
- {STATUS_LOG_PINNED, -EIO, "STATUS_LOG_PINNED"},
- {STATUS_LOG_METADATA_FLUSH_FAILED, -EIO,
- "STATUS_LOG_METADATA_FLUSH_FAILED"},
- {STATUS_LOG_INCONSISTENT_SECURITY, -EIO,
- "STATUS_LOG_INCONSISTENT_SECURITY"},
- {STATUS_LOG_APPENDED_FLUSH_FAILED, -EIO,
- "STATUS_LOG_APPENDED_FLUSH_FAILED"},
- {STATUS_LOG_PINNED_RESERVATION, -EIO, "STATUS_LOG_PINNED_RESERVATION"},
- {STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD, -EIO,
- "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD"},
- {STATUS_FLT_NO_HANDLER_DEFINED, -EIO, "STATUS_FLT_NO_HANDLER_DEFINED"},
- {STATUS_FLT_CONTEXT_ALREADY_DEFINED, -EIO,
- "STATUS_FLT_CONTEXT_ALREADY_DEFINED"},
- {STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST, -EIO,
- "STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST"},
- {STATUS_FLT_DISALLOW_FAST_IO, -EIO, "STATUS_FLT_DISALLOW_FAST_IO"},
- {STATUS_FLT_INVALID_NAME_REQUEST, -EIO,
- "STATUS_FLT_INVALID_NAME_REQUEST"},
- {STATUS_FLT_NOT_SAFE_TO_POST_OPERATION, -EIO,
- "STATUS_FLT_NOT_SAFE_TO_POST_OPERATION"},
- {STATUS_FLT_NOT_INITIALIZED, -EIO, "STATUS_FLT_NOT_INITIALIZED"},
- {STATUS_FLT_FILTER_NOT_READY, -EIO, "STATUS_FLT_FILTER_NOT_READY"},
- {STATUS_FLT_POST_OPERATION_CLEANUP, -EIO,
- "STATUS_FLT_POST_OPERATION_CLEANUP"},
- {STATUS_FLT_INTERNAL_ERROR, -EIO, "STATUS_FLT_INTERNAL_ERROR"},
- {STATUS_FLT_DELETING_OBJECT, -EIO, "STATUS_FLT_DELETING_OBJECT"},
- {STATUS_FLT_MUST_BE_NONPAGED_POOL, -EIO,
- "STATUS_FLT_MUST_BE_NONPAGED_POOL"},
- {STATUS_FLT_DUPLICATE_ENTRY, -EIO, "STATUS_FLT_DUPLICATE_ENTRY"},
- {STATUS_FLT_CBDQ_DISABLED, -EIO, "STATUS_FLT_CBDQ_DISABLED"},
- {STATUS_FLT_DO_NOT_ATTACH, -EIO, "STATUS_FLT_DO_NOT_ATTACH"},
- {STATUS_FLT_DO_NOT_DETACH, -EIO, "STATUS_FLT_DO_NOT_DETACH"},
- {STATUS_FLT_INSTANCE_ALTITUDE_COLLISION, -EIO,
- "STATUS_FLT_INSTANCE_ALTITUDE_COLLISION"},
- {STATUS_FLT_INSTANCE_NAME_COLLISION, -EIO,
- "STATUS_FLT_INSTANCE_NAME_COLLISION"},
- {STATUS_FLT_FILTER_NOT_FOUND, -EIO, "STATUS_FLT_FILTER_NOT_FOUND"},
- {STATUS_FLT_VOLUME_NOT_FOUND, -EIO, "STATUS_FLT_VOLUME_NOT_FOUND"},
- {STATUS_FLT_INSTANCE_NOT_FOUND, -EIO, "STATUS_FLT_INSTANCE_NOT_FOUND"},
- {STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND, -EIO,
- "STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND"},
- {STATUS_FLT_INVALID_CONTEXT_REGISTRATION, -EIO,
- "STATUS_FLT_INVALID_CONTEXT_REGISTRATION"},
- {STATUS_FLT_NAME_CACHE_MISS, -EIO, "STATUS_FLT_NAME_CACHE_MISS"},
- {STATUS_FLT_NO_DEVICE_OBJECT, -EIO, "STATUS_FLT_NO_DEVICE_OBJECT"},
- {STATUS_FLT_VOLUME_ALREADY_MOUNTED, -EIO,
- "STATUS_FLT_VOLUME_ALREADY_MOUNTED"},
- {STATUS_FLT_ALREADY_ENLISTED, -EIO, "STATUS_FLT_ALREADY_ENLISTED"},
- {STATUS_FLT_CONTEXT_ALREADY_LINKED, -EIO,
- "STATUS_FLT_CONTEXT_ALREADY_LINKED"},
- {STATUS_FLT_NO_WAITER_FOR_REPLY, -EIO,
- "STATUS_FLT_NO_WAITER_FOR_REPLY"},
- {STATUS_MONITOR_NO_DESCRIPTOR, -EIO, "STATUS_MONITOR_NO_DESCRIPTOR"},
- {STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT, -EIO,
- "STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT"},
- {STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM, -EIO,
- "STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM"},
- {STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK, -EIO,
- "STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK"},
- {STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED, -EIO,
- "STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED"},
- {STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK, -EIO,
- "STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK"},
- {STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK, -EIO,
- "STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK"},
- {STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA, -EIO,
- "STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA"},
- {STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK, -EIO,
- "STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK"},
- {STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER, -EIO,
- "STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER"},
- {STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER, -EIO,
- "STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER"},
- {STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER, -EIO,
- "STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER"},
- {STATUS_GRAPHICS_ADAPTER_WAS_RESET, -EIO,
- "STATUS_GRAPHICS_ADAPTER_WAS_RESET"},
- {STATUS_GRAPHICS_INVALID_DRIVER_MODEL, -EIO,
- "STATUS_GRAPHICS_INVALID_DRIVER_MODEL"},
- {STATUS_GRAPHICS_PRESENT_MODE_CHANGED, -EIO,
- "STATUS_GRAPHICS_PRESENT_MODE_CHANGED"},
- {STATUS_GRAPHICS_PRESENT_OCCLUDED, -EIO,
- "STATUS_GRAPHICS_PRESENT_OCCLUDED"},
- {STATUS_GRAPHICS_PRESENT_DENIED, -EIO,
- "STATUS_GRAPHICS_PRESENT_DENIED"},
- {STATUS_GRAPHICS_CANNOTCOLORCONVERT, -EIO,
- "STATUS_GRAPHICS_CANNOTCOLORCONVERT"},
- {STATUS_GRAPHICS_NO_VIDEO_MEMORY, -EIO,
- "STATUS_GRAPHICS_NO_VIDEO_MEMORY"},
- {STATUS_GRAPHICS_CANT_LOCK_MEMORY, -EIO,
- "STATUS_GRAPHICS_CANT_LOCK_MEMORY"},
- {STATUS_GRAPHICS_ALLOCATION_BUSY, -EBUSY,
- "STATUS_GRAPHICS_ALLOCATION_BUSY"},
- {STATUS_GRAPHICS_TOO_MANY_REFERENCES, -EIO,
- "STATUS_GRAPHICS_TOO_MANY_REFERENCES"},
- {STATUS_GRAPHICS_TRY_AGAIN_LATER, -EIO,
- "STATUS_GRAPHICS_TRY_AGAIN_LATER"},
- {STATUS_GRAPHICS_TRY_AGAIN_NOW, -EIO, "STATUS_GRAPHICS_TRY_AGAIN_NOW"},
- {STATUS_GRAPHICS_ALLOCATION_INVALID, -EIO,
- "STATUS_GRAPHICS_ALLOCATION_INVALID"},
- {STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE, -EIO,
- "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE"},
- {STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED, -EIO,
- "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED"},
- {STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION, -EIO,
- "STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION"},
- {STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE, -EIO,
- "STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE"},
- {STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION, -EIO,
- "STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION"},
- {STATUS_GRAPHICS_ALLOCATION_CLOSED, -EIO,
- "STATUS_GRAPHICS_ALLOCATION_CLOSED"},
- {STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE, -EIO,
- "STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE"},
- {STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE, -EIO,
- "STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE"},
- {STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE, -EIO,
- "STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE"},
- {STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST, -EIO,
- "STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST"},
- {STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE, -EIO,
- "STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE"},
- {STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY"},
- {STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_INVALID_VIDPN, -EIO, "STATUS_GRAPHICS_INVALID_VIDPN"},
- {STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE"},
- {STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET"},
- {STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET"},
- {STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET"},
- {STATUS_GRAPHICS_INVALID_FREQUENCY, -EIO,
- "STATUS_GRAPHICS_INVALID_FREQUENCY"},
- {STATUS_GRAPHICS_INVALID_ACTIVE_REGION, -EIO,
- "STATUS_GRAPHICS_INVALID_ACTIVE_REGION"},
- {STATUS_GRAPHICS_INVALID_TOTAL_REGION, -EIO,
- "STATUS_GRAPHICS_INVALID_TOTAL_REGION"},
- {STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE"},
- {STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE"},
- {STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET, -EIO,
- "STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET"},
- {STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY"},
- {STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET, -EIO,
- "STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET"},
- {STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET"},
- {STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET"},
- {STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET, -EIO,
- "STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET"},
- {STATUS_GRAPHICS_TARGET_ALREADY_IN_SET, -EIO,
- "STATUS_GRAPHICS_TARGET_ALREADY_IN_SET"},
- {STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH"},
- {STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY"},
- {STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET"},
- {STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE"},
- {STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET, -EIO,
- "STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET"},
- {STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET, -EIO,
- "STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET"},
- {STATUS_GRAPHICS_STALE_MODESET, -EIO, "STATUS_GRAPHICS_STALE_MODESET"},
- {STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET"},
- {STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE"},
- {STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN, -EIO,
- "STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN"},
- {STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE, -EIO,
- "STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE"},
- {STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION, -EIO,
- "STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION"},
- {STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES, -EIO,
- "STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES"},
- {STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY"},
- {STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE, -EIO,
- "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE"},
- {STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET, -EIO,
- "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET"},
- {STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET"},
- {STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR"},
- {STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET, -EIO,
- "STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET"},
- {STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET, -EIO,
- "STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET"},
- {STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE, -EIO,
- "STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE"},
- {STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE"},
- {STATUS_GRAPHICS_RESOURCES_NOT_RELATED, -EIO,
- "STATUS_GRAPHICS_RESOURCES_NOT_RELATED"},
- {STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE, -EIO,
- "STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE"},
- {STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE, -EIO,
- "STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE"},
- {STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET, -EIO,
- "STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET"},
- {STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER, -EIO,
- "STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER"},
- {STATUS_GRAPHICS_NO_VIDPNMGR, -EIO, "STATUS_GRAPHICS_NO_VIDPNMGR"},
- {STATUS_GRAPHICS_NO_ACTIVE_VIDPN, -EIO,
- "STATUS_GRAPHICS_NO_ACTIVE_VIDPN"},
- {STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY"},
- {STATUS_GRAPHICS_MONITOR_NOT_CONNECTED, -EIO,
- "STATUS_GRAPHICS_MONITOR_NOT_CONNECTED"},
- {STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY"},
- {STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE, -EIO,
- "STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE"},
- {STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE, -EIO,
- "STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE"},
- {STATUS_GRAPHICS_INVALID_STRIDE, -EIO,
- "STATUS_GRAPHICS_INVALID_STRIDE"},
- {STATUS_GRAPHICS_INVALID_PIXELFORMAT, -EIO,
- "STATUS_GRAPHICS_INVALID_PIXELFORMAT"},
- {STATUS_GRAPHICS_INVALID_COLORBASIS, -EIO,
- "STATUS_GRAPHICS_INVALID_COLORBASIS"},
- {STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE, -EIO,
- "STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE"},
- {STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY, -EIO,
- "STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY"},
- {STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT, -EIO,
- "STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT"},
- {STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, -EIO,
- "STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"},
- {STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN, -EIO,
- "STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN"},
- {STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL, -EIO,
- "STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL"},
- {STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION, -EIO,
- "STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION"},
- {STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED,
- -EIO,
- "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_INVALID_GAMMA_RAMP, -EIO,
- "STATUS_GRAPHICS_INVALID_GAMMA_RAMP"},
- {STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_MODE_NOT_IN_MODESET, -EIO,
- "STATUS_GRAPHICS_MODE_NOT_IN_MODESET"},
- {STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON, -EIO,
- "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON"},
- {STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE, -EIO,
- "STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE"},
- {STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE, -EIO,
- "STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE"},
- {STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS, -EIO,
- "STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS"},
- {STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING, -EIO,
- "STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING"},
- {STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED, -EIO,
- "STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED"},
- {STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS, -EIO,
- "STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS"},
- {STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT, -EIO,
- "STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT"},
- {STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM, -EIO,
- "STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM"},
- {STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN"},
- {STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT, -EIO,
- "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT"},
- {STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED, -EIO,
- "STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED"},
- {STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION, -EIO,
- "STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION"},
- {STATUS_GRAPHICS_INVALID_CLIENT_TYPE, -EIO,
- "STATUS_GRAPHICS_INVALID_CLIENT_TYPE"},
- {STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET, -EIO,
- "STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET"},
- {STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED, -EIO,
- "STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED"},
- {STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER, -EIO,
- "STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER"},
- {STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED, -EIO,
- "STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED"},
- {STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED, -EIO,
- "STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED"},
- {STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY, -EIO,
- "STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY"},
- {STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED, -EIO,
- "STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED"},
- {STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON, -EIO,
- "STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON"},
- {STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE, -EIO,
- "STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE"},
- {STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER, -EIO,
- "STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER"},
- {STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED, -EIO,
- "STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED"},
- {STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS,
- -EIO,
- "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS"},
- {STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST"},
- {STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR, -EIO,
- "STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR"},
- {STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS, -EIO,
- "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS"},
- {STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST"},
- {STATUS_GRAPHICS_OPM_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_OPM_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_COPP_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_COPP_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_UAB_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_UAB_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS"},
- {STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL, -EIO,
- "STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL"},
- {STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST, -EIO,
- "STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST"},
- {STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, -EIO,
- "STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"},
- {STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, -EIO,
- "STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"},
- {STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_OPM_INVALID_POINTER, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_POINTER"},
- {STATUS_GRAPHICS_OPM_INTERNAL_ERROR, -EIO,
- "STATUS_GRAPHICS_OPM_INTERNAL_ERROR"},
- {STATUS_GRAPHICS_OPM_INVALID_HANDLE, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_HANDLE"},
- {STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, -EIO,
- "STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"},
- {STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH, -EIO,
- "STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH"},
- {STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED, -EIO,
- "STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED"},
- {STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED, -EIO,
- "STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED"},
- {STATUS_GRAPHICS_PVP_HFS_FAILED, -EIO,
- "STATUS_GRAPHICS_PVP_HFS_FAILED"},
- {STATUS_GRAPHICS_OPM_INVALID_SRM, -EIO,
- "STATUS_GRAPHICS_OPM_INVALID_SRM"},
- {STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP, -EIO,
- "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP"},
- {STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP, -EIO,
- "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP"},
- {STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA, -EIO,
- "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA"},
- {STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET, -EIO,
- "STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET"},
- {STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH, -EIO,
- "STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH"},
- {STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE, -EIO,
- "STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE"},
- {STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS, -EIO,
- "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS"},
- {STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS, -EIO,
- "STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS"},
- {STATUS_GRAPHICS_I2C_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_I2C_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST, -EIO,
- "STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST"},
- {STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA, -EIO,
- "STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA"},
- {STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA, -EIO,
- "STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA"},
- {STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_DDCCI_INVALID_DATA, -EIO,
- "STATUS_GRAPHICS_DDCCI_INVALID_DATA"},
- {STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE,
- -EIO,
- "STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE"},
- {STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING, -EIO,
- "STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING"},
- {STATUS_GRAPHICS_MCA_INTERNAL_ERROR, -EIO,
- "STATUS_GRAPHICS_MCA_INTERNAL_ERROR"},
- {STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND, -EIO,
- "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND"},
- {STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH, -EIO,
- "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH"},
- {STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM, -EIO,
- "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM"},
- {STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE, -EIO,
- "STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE"},
- {STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS, -EIO,
- "STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS"},
- {STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED"},
- {STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, -EIO,
- "STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"},
- {STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, -EIO,
- "STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"},
- {STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED, -EIO,
- "STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED"},
- {STATUS_GRAPHICS_INVALID_POINTER, -EIO,
- "STATUS_GRAPHICS_INVALID_POINTER"},
- {STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, -EIO,
- "STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"},
- {STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL, -EIO,
- "STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL"},
- {STATUS_GRAPHICS_INTERNAL_ERROR, -EIO,
- "STATUS_GRAPHICS_INTERNAL_ERROR"},
- {STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS, -EIO,
- "STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS"},
- {STATUS_FVE_LOCKED_VOLUME, -EIO, "STATUS_FVE_LOCKED_VOLUME"},
- {STATUS_FVE_NOT_ENCRYPTED, -EIO, "STATUS_FVE_NOT_ENCRYPTED"},
- {STATUS_FVE_BAD_INFORMATION, -EIO, "STATUS_FVE_BAD_INFORMATION"},
- {STATUS_FVE_TOO_SMALL, -EIO, "STATUS_FVE_TOO_SMALL"},
- {STATUS_FVE_FAILED_WRONG_FS, -EIO, "STATUS_FVE_FAILED_WRONG_FS"},
- {STATUS_FVE_FAILED_BAD_FS, -EIO, "STATUS_FVE_FAILED_BAD_FS"},
- {STATUS_FVE_FS_NOT_EXTENDED, -EIO, "STATUS_FVE_FS_NOT_EXTENDED"},
- {STATUS_FVE_FS_MOUNTED, -EIO, "STATUS_FVE_FS_MOUNTED"},
- {STATUS_FVE_NO_LICENSE, -EIO, "STATUS_FVE_NO_LICENSE"},
- {STATUS_FVE_ACTION_NOT_ALLOWED, -EIO, "STATUS_FVE_ACTION_NOT_ALLOWED"},
- {STATUS_FVE_BAD_DATA, -EIO, "STATUS_FVE_BAD_DATA"},
- {STATUS_FVE_VOLUME_NOT_BOUND, -EIO, "STATUS_FVE_VOLUME_NOT_BOUND"},
- {STATUS_FVE_NOT_DATA_VOLUME, -EIO, "STATUS_FVE_NOT_DATA_VOLUME"},
- {STATUS_FVE_CONV_READ_ERROR, -EIO, "STATUS_FVE_CONV_READ_ERROR"},
- {STATUS_FVE_CONV_WRITE_ERROR, -EIO, "STATUS_FVE_CONV_WRITE_ERROR"},
- {STATUS_FVE_OVERLAPPED_UPDATE, -EIO, "STATUS_FVE_OVERLAPPED_UPDATE"},
- {STATUS_FVE_FAILED_SECTOR_SIZE, -EIO, "STATUS_FVE_FAILED_SECTOR_SIZE"},
- {STATUS_FVE_FAILED_AUTHENTICATION, -EIO,
- "STATUS_FVE_FAILED_AUTHENTICATION"},
- {STATUS_FVE_NOT_OS_VOLUME, -EIO, "STATUS_FVE_NOT_OS_VOLUME"},
- {STATUS_FVE_KEYFILE_NOT_FOUND, -EIO, "STATUS_FVE_KEYFILE_NOT_FOUND"},
- {STATUS_FVE_KEYFILE_INVALID, -EIO, "STATUS_FVE_KEYFILE_INVALID"},
- {STATUS_FVE_KEYFILE_NO_VMK, -EIO, "STATUS_FVE_KEYFILE_NO_VMK"},
- {STATUS_FVE_TPM_DISABLED, -EIO, "STATUS_FVE_TPM_DISABLED"},
- {STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO, -EIO,
- "STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO"},
- {STATUS_FVE_TPM_INVALID_PCR, -EIO, "STATUS_FVE_TPM_INVALID_PCR"},
- {STATUS_FVE_TPM_NO_VMK, -EIO, "STATUS_FVE_TPM_NO_VMK"},
- {STATUS_FVE_PIN_INVALID, -EIO, "STATUS_FVE_PIN_INVALID"},
- {STATUS_FVE_AUTH_INVALID_APPLICATION, -EIO,
- "STATUS_FVE_AUTH_INVALID_APPLICATION"},
- {STATUS_FVE_AUTH_INVALID_CONFIG, -EIO,
- "STATUS_FVE_AUTH_INVALID_CONFIG"},
- {STATUS_FVE_DEBUGGER_ENABLED, -EIO, "STATUS_FVE_DEBUGGER_ENABLED"},
- {STATUS_FVE_DRY_RUN_FAILED, -EIO, "STATUS_FVE_DRY_RUN_FAILED"},
- {STATUS_FVE_BAD_METADATA_POINTER, -EIO,
- "STATUS_FVE_BAD_METADATA_POINTER"},
- {STATUS_FVE_OLD_METADATA_COPY, -EIO, "STATUS_FVE_OLD_METADATA_COPY"},
- {STATUS_FVE_REBOOT_REQUIRED, -EIO, "STATUS_FVE_REBOOT_REQUIRED"},
- {STATUS_FVE_RAW_ACCESS, -EIO, "STATUS_FVE_RAW_ACCESS"},
- {STATUS_FVE_RAW_BLOCKED, -EIO, "STATUS_FVE_RAW_BLOCKED"},
- {STATUS_FWP_CALLOUT_NOT_FOUND, -EIO, "STATUS_FWP_CALLOUT_NOT_FOUND"},
- {STATUS_FWP_CONDITION_NOT_FOUND, -EIO,
- "STATUS_FWP_CONDITION_NOT_FOUND"},
- {STATUS_FWP_FILTER_NOT_FOUND, -EIO, "STATUS_FWP_FILTER_NOT_FOUND"},
- {STATUS_FWP_LAYER_NOT_FOUND, -EIO, "STATUS_FWP_LAYER_NOT_FOUND"},
- {STATUS_FWP_PROVIDER_NOT_FOUND, -EIO, "STATUS_FWP_PROVIDER_NOT_FOUND"},
- {STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND, -EIO,
- "STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND"},
- {STATUS_FWP_SUBLAYER_NOT_FOUND, -EIO, "STATUS_FWP_SUBLAYER_NOT_FOUND"},
- {STATUS_FWP_NOT_FOUND, -EIO, "STATUS_FWP_NOT_FOUND"},
- {STATUS_FWP_ALREADY_EXISTS, -EIO, "STATUS_FWP_ALREADY_EXISTS"},
- {STATUS_FWP_IN_USE, -EIO, "STATUS_FWP_IN_USE"},
- {STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS, -EIO,
- "STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS"},
- {STATUS_FWP_WRONG_SESSION, -EIO, "STATUS_FWP_WRONG_SESSION"},
- {STATUS_FWP_NO_TXN_IN_PROGRESS, -EIO, "STATUS_FWP_NO_TXN_IN_PROGRESS"},
- {STATUS_FWP_TXN_IN_PROGRESS, -EIO, "STATUS_FWP_TXN_IN_PROGRESS"},
- {STATUS_FWP_TXN_ABORTED, -EIO, "STATUS_FWP_TXN_ABORTED"},
- {STATUS_FWP_SESSION_ABORTED, -EIO, "STATUS_FWP_SESSION_ABORTED"},
- {STATUS_FWP_INCOMPATIBLE_TXN, -EIO, "STATUS_FWP_INCOMPATIBLE_TXN"},
- {STATUS_FWP_TIMEOUT, -ETIMEDOUT, "STATUS_FWP_TIMEOUT"},
- {STATUS_FWP_NET_EVENTS_DISABLED, -EIO,
- "STATUS_FWP_NET_EVENTS_DISABLED"},
- {STATUS_FWP_INCOMPATIBLE_LAYER, -EIO, "STATUS_FWP_INCOMPATIBLE_LAYER"},
- {STATUS_FWP_KM_CLIENTS_ONLY, -EIO, "STATUS_FWP_KM_CLIENTS_ONLY"},
- {STATUS_FWP_LIFETIME_MISMATCH, -EIO, "STATUS_FWP_LIFETIME_MISMATCH"},
- {STATUS_FWP_BUILTIN_OBJECT, -EIO, "STATUS_FWP_BUILTIN_OBJECT"},
- {STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS, -EIO,
- "STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS"},
- {STATUS_FWP_TOO_MANY_CALLOUTS, -EIO, "STATUS_FWP_TOO_MANY_CALLOUTS"},
- {STATUS_FWP_NOTIFICATION_DROPPED, -EIO,
- "STATUS_FWP_NOTIFICATION_DROPPED"},
- {STATUS_FWP_TRAFFIC_MISMATCH, -EIO, "STATUS_FWP_TRAFFIC_MISMATCH"},
- {STATUS_FWP_INCOMPATIBLE_SA_STATE, -EIO,
- "STATUS_FWP_INCOMPATIBLE_SA_STATE"},
- {STATUS_FWP_NULL_POINTER, -EIO, "STATUS_FWP_NULL_POINTER"},
- {STATUS_FWP_INVALID_ENUMERATOR, -EIO, "STATUS_FWP_INVALID_ENUMERATOR"},
- {STATUS_FWP_INVALID_FLAGS, -EIO, "STATUS_FWP_INVALID_FLAGS"},
- {STATUS_FWP_INVALID_NET_MASK, -EIO, "STATUS_FWP_INVALID_NET_MASK"},
- {STATUS_FWP_INVALID_RANGE, -EIO, "STATUS_FWP_INVALID_RANGE"},
- {STATUS_FWP_INVALID_INTERVAL, -EIO, "STATUS_FWP_INVALID_INTERVAL"},
- {STATUS_FWP_ZERO_LENGTH_ARRAY, -EIO, "STATUS_FWP_ZERO_LENGTH_ARRAY"},
- {STATUS_FWP_NULL_DISPLAY_NAME, -EIO, "STATUS_FWP_NULL_DISPLAY_NAME"},
- {STATUS_FWP_INVALID_ACTION_TYPE, -EIO,
- "STATUS_FWP_INVALID_ACTION_TYPE"},
- {STATUS_FWP_INVALID_WEIGHT, -EIO, "STATUS_FWP_INVALID_WEIGHT"},
- {STATUS_FWP_MATCH_TYPE_MISMATCH, -EIO,
- "STATUS_FWP_MATCH_TYPE_MISMATCH"},
- {STATUS_FWP_TYPE_MISMATCH, -EIO, "STATUS_FWP_TYPE_MISMATCH"},
- {STATUS_FWP_OUT_OF_BOUNDS, -EIO, "STATUS_FWP_OUT_OF_BOUNDS"},
- {STATUS_FWP_RESERVED, -EIO, "STATUS_FWP_RESERVED"},
- {STATUS_FWP_DUPLICATE_CONDITION, -EIO,
- "STATUS_FWP_DUPLICATE_CONDITION"},
- {STATUS_FWP_DUPLICATE_KEYMOD, -EIO, "STATUS_FWP_DUPLICATE_KEYMOD"},
- {STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER, -EIO,
- "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER"},
- {STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER, -EIO,
- "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER"},
- {STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER, -EIO,
- "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER"},
- {STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT, -EIO,
- "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT"},
- {STATUS_FWP_INCOMPATIBLE_AUTH_METHOD, -EIO,
- "STATUS_FWP_INCOMPATIBLE_AUTH_METHOD"},
- {STATUS_FWP_INCOMPATIBLE_DH_GROUP, -EIO,
- "STATUS_FWP_INCOMPATIBLE_DH_GROUP"},
- {STATUS_FWP_EM_NOT_SUPPORTED, -EOPNOTSUPP,
- "STATUS_FWP_EM_NOT_SUPPORTED"},
- {STATUS_FWP_NEVER_MATCH, -EIO, "STATUS_FWP_NEVER_MATCH"},
- {STATUS_FWP_PROVIDER_CONTEXT_MISMATCH, -EIO,
- "STATUS_FWP_PROVIDER_CONTEXT_MISMATCH"},
- {STATUS_FWP_INVALID_PARAMETER, -EIO, "STATUS_FWP_INVALID_PARAMETER"},
- {STATUS_FWP_TOO_MANY_SUBLAYERS, -EIO, "STATUS_FWP_TOO_MANY_SUBLAYERS"},
- {STATUS_FWP_CALLOUT_NOTIFICATION_FAILED, -EIO,
- "STATUS_FWP_CALLOUT_NOTIFICATION_FAILED"},
- {STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG, -EIO,
- "STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG"},
- {STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG, -EIO,
- "STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG"},
- {STATUS_FWP_TCPIP_NOT_READY, -EIO, "STATUS_FWP_TCPIP_NOT_READY"},
- {STATUS_FWP_INJECT_HANDLE_CLOSING, -EIO,
- "STATUS_FWP_INJECT_HANDLE_CLOSING"},
- {STATUS_FWP_INJECT_HANDLE_STALE, -EIO,
- "STATUS_FWP_INJECT_HANDLE_STALE"},
- {STATUS_FWP_CANNOT_PEND, -EIO, "STATUS_FWP_CANNOT_PEND"},
- {STATUS_NDIS_CLOSING, -EIO, "STATUS_NDIS_CLOSING"},
- {STATUS_NDIS_BAD_VERSION, -EIO, "STATUS_NDIS_BAD_VERSION"},
- {STATUS_NDIS_BAD_CHARACTERISTICS, -EIO,
- "STATUS_NDIS_BAD_CHARACTERISTICS"},
- {STATUS_NDIS_ADAPTER_NOT_FOUND, -EIO, "STATUS_NDIS_ADAPTER_NOT_FOUND"},
- {STATUS_NDIS_OPEN_FAILED, -EIO, "STATUS_NDIS_OPEN_FAILED"},
- {STATUS_NDIS_DEVICE_FAILED, -EIO, "STATUS_NDIS_DEVICE_FAILED"},
- {STATUS_NDIS_MULTICAST_FULL, -EIO, "STATUS_NDIS_MULTICAST_FULL"},
- {STATUS_NDIS_MULTICAST_EXISTS, -EIO, "STATUS_NDIS_MULTICAST_EXISTS"},
- {STATUS_NDIS_MULTICAST_NOT_FOUND, -EIO,
- "STATUS_NDIS_MULTICAST_NOT_FOUND"},
- {STATUS_NDIS_REQUEST_ABORTED, -EIO, "STATUS_NDIS_REQUEST_ABORTED"},
- {STATUS_NDIS_RESET_IN_PROGRESS, -EIO, "STATUS_NDIS_RESET_IN_PROGRESS"},
- {STATUS_NDIS_INVALID_PACKET, -EIO, "STATUS_NDIS_INVALID_PACKET"},
- {STATUS_NDIS_INVALID_DEVICE_REQUEST, -EIO,
- "STATUS_NDIS_INVALID_DEVICE_REQUEST"},
- {STATUS_NDIS_ADAPTER_NOT_READY, -EIO, "STATUS_NDIS_ADAPTER_NOT_READY"},
- {STATUS_NDIS_INVALID_LENGTH, -EIO, "STATUS_NDIS_INVALID_LENGTH"},
- {STATUS_NDIS_INVALID_DATA, -EIO, "STATUS_NDIS_INVALID_DATA"},
- {STATUS_NDIS_BUFFER_TOO_SHORT, -ENOBUFS,
- "STATUS_NDIS_BUFFER_TOO_SHORT"},
- {STATUS_NDIS_INVALID_OID, -EIO, "STATUS_NDIS_INVALID_OID"},
- {STATUS_NDIS_ADAPTER_REMOVED, -EIO, "STATUS_NDIS_ADAPTER_REMOVED"},
- {STATUS_NDIS_UNSUPPORTED_MEDIA, -EIO, "STATUS_NDIS_UNSUPPORTED_MEDIA"},
- {STATUS_NDIS_GROUP_ADDRESS_IN_USE, -EIO,
- "STATUS_NDIS_GROUP_ADDRESS_IN_USE"},
- {STATUS_NDIS_FILE_NOT_FOUND, -EIO, "STATUS_NDIS_FILE_NOT_FOUND"},
- {STATUS_NDIS_ERROR_READING_FILE, -EIO,
- "STATUS_NDIS_ERROR_READING_FILE"},
- {STATUS_NDIS_ALREADY_MAPPED, -EIO, "STATUS_NDIS_ALREADY_MAPPED"},
- {STATUS_NDIS_RESOURCE_CONFLICT, -EIO, "STATUS_NDIS_RESOURCE_CONFLICT"},
- {STATUS_NDIS_MEDIA_DISCONNECTED, -EIO,
- "STATUS_NDIS_MEDIA_DISCONNECTED"},
- {STATUS_NDIS_INVALID_ADDRESS, -EIO, "STATUS_NDIS_INVALID_ADDRESS"},
- {STATUS_NDIS_PAUSED, -EIO, "STATUS_NDIS_PAUSED"},
- {STATUS_NDIS_INTERFACE_NOT_FOUND, -EIO,
- "STATUS_NDIS_INTERFACE_NOT_FOUND"},
- {STATUS_NDIS_UNSUPPORTED_REVISION, -EIO,
- "STATUS_NDIS_UNSUPPORTED_REVISION"},
- {STATUS_NDIS_INVALID_PORT, -EIO, "STATUS_NDIS_INVALID_PORT"},
- {STATUS_NDIS_INVALID_PORT_STATE, -EIO,
- "STATUS_NDIS_INVALID_PORT_STATE"},
- {STATUS_NDIS_LOW_POWER_STATE, -EIO, "STATUS_NDIS_LOW_POWER_STATE"},
- {STATUS_NDIS_NOT_SUPPORTED, -ENOSYS, "STATUS_NDIS_NOT_SUPPORTED"},
- {STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED, -EIO,
- "STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED"},
- {STATUS_NDIS_DOT11_MEDIA_IN_USE, -EIO,
- "STATUS_NDIS_DOT11_MEDIA_IN_USE"},
- {STATUS_NDIS_DOT11_POWER_STATE_INVALID, -EIO,
- "STATUS_NDIS_DOT11_POWER_STATE_INVALID"},
- {STATUS_IPSEC_BAD_SPI, -EIO, "STATUS_IPSEC_BAD_SPI"},
- {STATUS_IPSEC_SA_LIFETIME_EXPIRED, -EIO,
- "STATUS_IPSEC_SA_LIFETIME_EXPIRED"},
- {STATUS_IPSEC_WRONG_SA, -EIO, "STATUS_IPSEC_WRONG_SA"},
- {STATUS_IPSEC_REPLAY_CHECK_FAILED, -EIO,
- "STATUS_IPSEC_REPLAY_CHECK_FAILED"},
- {STATUS_IPSEC_INVALID_PACKET, -EIO, "STATUS_IPSEC_INVALID_PACKET"},
- {STATUS_IPSEC_INTEGRITY_CHECK_FAILED, -EIO,
- "STATUS_IPSEC_INTEGRITY_CHECK_FAILED"},
- {STATUS_IPSEC_CLEAR_TEXT_DROP, -EIO, "STATUS_IPSEC_CLEAR_TEXT_DROP"},
- {0, 0, NULL}
+/*
+ * Automatically generated by the `gen_smb2_mapping` script,
+ * sorted by NT status code (cpu-endian, ascending)
+ */
+#include "smb2_mapping_table.c"
};
-/*****************************************************************************
- Print an error message from the status code
- *****************************************************************************/
-static void
-smb2_print_status(__le32 status)
+static __always_inline int cmp_smb2_status(const void *_key, const void *_pivot)
{
- int idx = 0;
+ __u32 key = *(__u32 *)_key;
+ const struct status_to_posix_error *pivot = _pivot;
- while (smb2_error_map_table[idx].status_string != NULL) {
- if ((smb2_error_map_table[idx].smb2_status) == status) {
- pr_notice("Status code returned 0x%08x %s\n", status,
- smb2_error_map_table[idx].status_string);
- }
- idx++;
- }
- return;
+ if (key < pivot->smb2_status)
+ return -1;
+ if (key > pivot->smb2_status)
+ return 1;
+ return 0;
+}
+
+static const struct status_to_posix_error *smb2_get_err_map(__u32 smb2_status)
+{
+ const struct status_to_posix_error *err_map;
+
+ err_map = __inline_bsearch(&smb2_status, smb2_error_map_table,
+ ARRAY_SIZE(smb2_error_map_table),
+ sizeof(struct status_to_posix_error),
+ cmp_smb2_status);
+ return err_map;
}
int
map_smb2_to_linux_error(char *buf, bool log_err)
{
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
- unsigned int i;
int rc = -EIO;
__le32 smb2err = shdr->Status;
+ const struct status_to_posix_error *err_map;
if (smb2err == 0) {
trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId),
@@ -2452,30 +62,65 @@ map_smb2_to_linux_error(char *buf, bool log_err)
return 0;
}
- /* mask facility */
- if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
- (smb2err != STATUS_END_OF_FILE))
- smb2_print_status(smb2err);
- else if (cifsFYI & CIFS_RC)
- smb2_print_status(smb2err);
+ log_err = (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
+ (smb2err != STATUS_END_OF_FILE)) ||
+ (cifsFYI & CIFS_RC);
- for (i = 0; i < sizeof(smb2_error_map_table) /
- sizeof(struct status_to_posix_error); i++) {
- if (smb2_error_map_table[i].smb2_status == smb2err) {
- rc = smb2_error_map_table[i].posix_error;
- break;
- }
- }
+ err_map = smb2_get_err_map(le32_to_cpu(smb2err));
+ if (!err_map)
+ goto out;
+
+ rc = err_map->posix_error;
+ if (log_err)
+ pr_notice("Status code returned 0x%08x %s\n",
+ err_map->smb2_status, err_map->status_string);
+out:
/* on error mapping not found - return EIO */
cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n",
- __le32_to_cpu(smb2err), rc);
+ le32_to_cpu(smb2err), rc);
trace_smb3_cmd_err(le32_to_cpu(shdr->Id.SyncId.TreeId),
le64_to_cpu(shdr->SessionId),
le16_to_cpu(shdr->Command),
le64_to_cpu(shdr->MessageId),
le32_to_cpu(smb2err), rc);
+ if (rc == -EIO)
+ smb_EIO1(smb_eio_trace_smb2_received_error, le32_to_cpu(smb2err));
return rc;
}
+
+int __init smb2_init_maperror(void)
+{
+ unsigned int i;
+
+ /* Check whether the array is sorted in ascending order */
+ for (i = 1; i < ARRAY_SIZE(smb2_error_map_table); i++) {
+ if (smb2_error_map_table[i].smb2_status >=
+ smb2_error_map_table[i - 1].smb2_status)
+ continue;
+
+ pr_err("smb2_error_map_table array order is incorrect\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
+#define EXPORT_SYMBOL_FOR_SMB_TEST(sym) \
+ EXPORT_SYMBOL_FOR_MODULES(sym, "smb2maperror_test")
+
+const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status)
+{
+ return smb2_get_err_map(smb2_status);
+}
+EXPORT_SYMBOL_FOR_SMB_TEST(smb2_get_err_map_test);
+
+const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table;
+EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_table_test);
+
+unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table);
+EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_num);
+#endif
diff --git a/fs/smb/client/smb2maperror_test.c b/fs/smb/client/smb2maperror_test.c
new file mode 100644
index 000000000000..0f8a44a5ed3c
--- /dev/null
+++ b/fs/smb/client/smb2maperror_test.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ * KUnit tests of SMB2 maperror
+ *
+ * Copyright (C) 2025 KylinSoft Co., Ltd. All rights reserved.
+ * Author(s): ChenXiaoSong <chenxiaosong@kylinos.cn>
+ *
+ */
+
+#include <kunit/test.h>
+#include "cifsglob.h"
+#include "smb2glob.h"
+#include "smb2proto.h"
+
+static void
+test_cmp_map(struct kunit *test, const struct status_to_posix_error *expect)
+{
+ const struct status_to_posix_error *result;
+
+ result = smb2_get_err_map_test(expect->smb2_status);
+ KUNIT_ASSERT_NOT_NULL(test, result);
+ KUNIT_EXPECT_EQ(test, expect->smb2_status, result->smb2_status);
+ KUNIT_EXPECT_EQ(test, expect->posix_error, result->posix_error);
+ KUNIT_EXPECT_STREQ(test, expect->status_string, result->status_string);
+}
+
+static void maperror_test_check_search(struct kunit *test)
+{
+ unsigned int i;
+
+ for (i = 0; i < smb2_error_map_num; i++)
+ test_cmp_map(test, &smb2_error_map_table_test[i]);
+}
+
+static struct kunit_case maperror_test_cases[] = {
+ KUNIT_CASE(maperror_test_check_search),
+ {}
+};
+
+static struct kunit_suite maperror_suite = {
+ .name = "smb2_maperror",
+ .test_cases = maperror_test_cases,
+};
+
+kunit_test_suite(maperror_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests of SMB2 maperror");
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index cddf273c14ae..973fce3c959c 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -7,6 +7,7 @@
* Pavel Shilovsky (pshilovsky@samba.org) 2012
*
*/
+#include <crypto/sha2.h>
#include <linux/ctype.h>
#include "cifsglob.h"
#include "cifsproto.h"
@@ -133,7 +134,8 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len,
}
int
-smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
+smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
+ struct TCP_Server_Info *server)
{
struct TCP_Server_Info *pserver;
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
@@ -453,17 +455,8 @@ calc_size_exit:
__le16 *
cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
{
- int len;
const char *start_of_path;
- __le16 *to;
- int map_type;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
- map_type = SFM_MAP_UNI_RSVD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
- map_type = SFU_MAP_UNI_RSVD;
- else
- map_type = NO_MAP_UNI_RSVD;
+ int len;
/* Windows doesn't allow paths beginning with \ */
if (from[0] == '\\')
@@ -477,21 +470,20 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
} else
start_of_path = from;
- to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
- cifs_sb->local_nls, map_type);
- return to;
+ return cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
+ cifs_sb->local_nls, cifs_remap(cifs_sb));
}
-__le32
-smb2_get_lease_state(struct cifsInodeInfo *cinode)
+__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock)
{
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
__le32 lease = 0;
- if (CIFS_CACHE_WRITE(cinode))
+ if ((oplock & CIFS_CACHE_WRITE_FLG) || (sbflags & CIFS_MOUNT_RW_CACHE))
lease |= SMB2_LEASE_WRITE_CACHING_LE;
- if (CIFS_CACHE_HANDLE(cinode))
+ if (oplock & CIFS_CACHE_HANDLE_FLG)
lease |= SMB2_LEASE_HANDLE_CACHING_LE;
- if (CIFS_CACHE_READ(cinode))
+ if ((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE))
lease |= SMB2_LEASE_READ_CACHING_LE;
return lease;
}
@@ -524,7 +516,7 @@ smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key,
{
struct smb2_lease_break_work *lw;
- lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
+ lw = kmalloc_obj(struct smb2_lease_break_work);
if (!lw) {
cifs_put_tlink(tlink);
return;
@@ -614,6 +606,15 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
struct cifs_tcon *tcon;
struct cifs_pending_open *open;
+ /* Trace receipt of lease break request from server */
+ trace_smb3_lease_break_enter(le32_to_cpu(rsp->CurrentLeaseState),
+ le32_to_cpu(rsp->Flags),
+ le16_to_cpu(rsp->Epoch),
+ le32_to_cpu(rsp->hdr.Id.SyncId.TreeId),
+ le64_to_cpu(rsp->hdr.SessionId),
+ *((u64 *)rsp->LeaseKey),
+ *((u64 *)&rsp->LeaseKey[8]));
+
cifs_dbg(FYI, "Checking for lease break\n");
/* If server is a channel, select the primary channel */
@@ -660,10 +661,12 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
trace_smb3_lease_not_found(le32_to_cpu(rsp->CurrentLeaseState),
- le32_to_cpu(rsp->hdr.Id.SyncId.TreeId),
- le64_to_cpu(rsp->hdr.SessionId),
- *((u64 *)rsp->LeaseKey),
- *((u64 *)&rsp->LeaseKey[8]));
+ le32_to_cpu(rsp->Flags),
+ le16_to_cpu(rsp->Epoch),
+ le32_to_cpu(rsp->hdr.Id.SyncId.TreeId),
+ le64_to_cpu(rsp->hdr.SessionId),
+ *((u64 *)rsp->LeaseKey),
+ *((u64 *)&rsp->LeaseKey[8]));
return false;
}
@@ -785,7 +788,7 @@ __smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid,
{
struct close_cancelled_open *cancelled;
- cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
+ cancelled = kzalloc_obj(*cancelled);
if (!cancelled)
return -ENOMEM;
@@ -807,14 +810,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
int rc;
cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
- spin_lock(&cifs_tcp_ses_lock);
+ spin_lock(&tcon->tc_lock);
if (tcon->tc_count <= 0) {
struct TCP_Server_Info *server = NULL;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_cancelled_close);
WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative");
- spin_unlock(&cifs_tcp_ses_lock);
+ spin_unlock(&tcon->tc_lock);
if (tcon->ses) {
server = tcon->ses->server;
@@ -828,7 +831,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
tcon->tc_count++;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_cancelled_close);
- spin_unlock(&cifs_tcp_ses_lock);
+ spin_unlock(&tcon->tc_lock);
rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0,
persistent_fid, volatile_fid);
@@ -877,13 +880,13 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve
* @iov: array containing the SMB request we will send to the server
* @nvec: number of array entries for the iov
*/
-int
+void
smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
struct kvec *iov, int nvec)
{
- int i, rc;
+ int i;
struct smb2_hdr *hdr;
- struct shash_desc *sha512 = NULL;
+ struct sha512_ctx sha_ctx;
hdr = (struct smb2_hdr *)iov[0].iov_base;
/* neg prot are always taken */
@@ -896,52 +899,22 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
* and we can test it. Preauth requires 3.1.1 for now.
*/
if (server->dialect != SMB311_PROT_ID)
- return 0;
+ return;
if (hdr->Command != SMB2_SESSION_SETUP)
- return 0;
+ return;
/* skip last sess setup response */
if ((hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
&& (hdr->Status == NT_STATUS_OK
|| (hdr->Status !=
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))))
- return 0;
+ return;
ok:
- rc = smb311_crypto_shash_allocate(server);
- if (rc)
- return rc;
-
- sha512 = server->secmech.sha512;
- rc = crypto_shash_init(sha512);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__);
- return rc;
- }
-
- rc = crypto_shash_update(sha512, ses->preauth_sha_hash,
- SMB2_PREAUTH_HASH_SIZE);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__);
- return rc;
- }
-
- for (i = 0; i < nvec; i++) {
- rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not update sha512 shash\n",
- __func__);
- return rc;
- }
- }
-
- rc = crypto_shash_final(sha512, ses->preauth_sha_hash);
- if (rc) {
- cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n",
- __func__);
- return rc;
- }
-
- return 0;
+ sha512_init(&sha_ctx);
+ sha512_update(&sha_ctx, ses->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE);
+ for (i = 0; i < nvec; i++)
+ sha512_update(&sha_ctx, iov[i].iov_base, iov[i].iov_len);
+ sha512_final(&sha_ctx, ses->preauth_sha_hash);
}
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 2fe8eeb98535..7f346ee50289 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -17,9 +17,9 @@
#include <uapi/linux/magic.h>
#include "cifsfs.h"
#include "cifsglob.h"
-#include "smb2pdu.h"
-#include "smb2proto.h"
#include "cifsproto.h"
+#include "smb2proto.h"
+#include "smb2pdu.h"
#include "cifs_debug.h"
#include "cifs_unicode.h"
#include "../common/smb2status.h"
@@ -91,7 +91,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
if (*val > 65000) {
*val = 65000; /* Don't get near 64K credits, avoid srv bugs */
pr_warn_once("server overflowed SMB3 credits\n");
- trace_smb3_overflow_credits(server->CurrentMid,
+ trace_smb3_overflow_credits(server->current_mid,
server->conn_id, server->hostname, *val,
add, server->in_flight);
}
@@ -136,7 +136,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
wake_up(&server->request_q);
if (reconnect_detected) {
- trace_smb3_reconnect_detected(server->CurrentMid,
+ trace_smb3_reconnect_detected(server->current_mid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
@@ -144,7 +144,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
}
if (reconnect_with_invalid_credits) {
- trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
+ trace_smb3_reconnect_with_invalid_credits(server->current_mid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "Negotiate operation when server credits is non-zero. Optype: %d, server credits: %d, credits added: %d\n",
optype, scredits, add);
@@ -176,7 +176,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
break;
}
- trace_smb3_add_credits(server->CurrentMid,
+ trace_smb3_add_credits(server->current_mid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, scredits);
}
@@ -203,7 +203,7 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
- trace_smb3_set_credits(server->CurrentMid,
+ trace_smb3_set_credits(server->current_mid,
server->conn_id, server->hostname, scredits, val, in_flight);
cifs_dbg(FYI, "%s: set %u credits\n", __func__, val);
@@ -288,7 +288,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
- trace_smb3_wait_credits(server->CurrentMid,
+ trace_smb3_wait_credits(server->current_mid,
server->conn_id, server->hostname, scredits, -(credits->value), in_flight);
cifs_dbg(FYI, "%s: removed %u credits total=%d\n",
__func__, credits->value, scredits);
@@ -316,7 +316,7 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
server->credits, server->in_flight,
new_val - credits->value,
cifs_trace_rw_credits_no_adjust_up);
- trace_smb3_too_many_credits(server->CurrentMid,
+ trace_smb3_too_many_credits(server->current_mid,
server->conn_id, server->hostname, 0, credits->value - new_val, 0);
cifs_server_dbg(VFS, "R=%x[%x] request has less credits (%d) than required (%d)",
subreq->rreq->debug_id, subreq->subreq.debug_index,
@@ -338,7 +338,7 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
server->credits, server->in_flight,
new_val - credits->value,
cifs_trace_rw_credits_old_session);
- trace_smb3_reconnect_detected(server->CurrentMid,
+ trace_smb3_reconnect_detected(server->current_mid,
server->conn_id, server->hostname, scredits,
credits->value - new_val, in_flight);
cifs_server_dbg(VFS, "R=%x[%x] trying to return %d credits to old session\n",
@@ -358,7 +358,7 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
- trace_smb3_adj_credits(server->CurrentMid,
+ trace_smb3_adj_credits(server->current_mid,
server->conn_id, server->hostname, scredits,
credits->value - new_val, in_flight);
cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n",
@@ -374,19 +374,19 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
{
__u64 mid;
/* for SMB2 we need the current value */
- spin_lock(&server->mid_lock);
- mid = server->CurrentMid++;
- spin_unlock(&server->mid_lock);
+ spin_lock(&server->mid_counter_lock);
+ mid = server->current_mid++;
+ spin_unlock(&server->mid_counter_lock);
return mid;
}
static void
smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
{
- spin_lock(&server->mid_lock);
- if (server->CurrentMid >= val)
- server->CurrentMid -= val;
- spin_unlock(&server->mid_lock);
+ spin_lock(&server->mid_counter_lock);
+ if (server->current_mid >= val)
+ server->current_mid -= val;
+ spin_unlock(&server->mid_counter_lock);
}
static struct mid_q_entry *
@@ -401,21 +401,21 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
return NULL;
}
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_for_each_entry(mid, &server->pending_mid_q, qhead) {
if ((mid->mid == wire_mid) &&
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
(mid->command == shdr->Command)) {
- kref_get(&mid->refcount);
+ smb_get_mid(mid);
if (dequeue) {
list_del_init(&mid->qhead);
- mid->mid_flags |= MID_DELETED;
+ mid->deleted_from_q = true;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
return mid;
}
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
return NULL;
}
@@ -432,7 +432,7 @@ smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
}
static void
-smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
+smb2_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server)
{
#ifdef CONFIG_CIFS_DEBUG2
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
@@ -440,7 +440,7 @@ smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
shdr->Id.SyncId.ProcessId);
- if (!server->ops->check_message(buf, server->total_read, server)) {
+ if (!server->ops->check_message(buf, buf_len, server->total_read, server)) {
cifs_server_dbg(VFS, "smb buf %p len %u\n", buf,
server->ops->calc_smb_size(buf));
}
@@ -460,9 +460,9 @@ smb2_negotiate(const unsigned int xid,
{
int rc;
- spin_lock(&server->mid_lock);
- server->CurrentMid = 0;
- spin_unlock(&server->mid_lock);
+ spin_lock(&server->mid_counter_lock);
+ server->current_mid = 0;
+ spin_unlock(&server->mid_counter_lock);
rc = SMB2_negotiate(xid, ses, server);
return rc;
}
@@ -504,6 +504,9 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
wsize = min_t(unsigned int, wsize, server->max_write);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
+ const struct smbdirect_socket_parameters *sp =
+ smbd_get_parameters(server->smbd_conn);
+
if (server->sign)
/*
* Account for SMB2 data transfer packet header and
@@ -511,12 +514,12 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
*/
wsize = min_t(unsigned int,
wsize,
- server->smbd_conn->max_fragmented_send_size -
+ sp->max_fragmented_send_size -
SMB2_READWRITE_PDU_HEADER_SIZE -
sizeof(struct smb2_transform_hdr));
else
wsize = min_t(unsigned int,
- wsize, server->smbd_conn->max_readwrite_size);
+ wsize, sp->max_read_write_size);
}
#endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
@@ -552,6 +555,9 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
rsize = min_t(unsigned int, rsize, server->max_read);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
+ const struct smbdirect_socket_parameters *sp =
+ smbd_get_parameters(server->smbd_conn);
+
if (server->sign)
/*
* Account for SMB2 data transfer packet header and
@@ -559,12 +565,12 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
*/
rsize = min_t(unsigned int,
rsize,
- server->smbd_conn->max_fragmented_recv_size -
+ sp->max_fragmented_recv_size -
SMB2_READWRITE_PDU_HEADER_SIZE -
sizeof(struct smb2_transform_hdr));
else
rsize = min_t(unsigned int,
- rsize, server->smbd_conn->max_readwrite_size);
+ rsize, sp->max_read_write_size);
}
#endif
@@ -618,10 +624,11 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
struct network_interface_info_ioctl_rsp *p;
struct sockaddr_in *addr4;
struct sockaddr_in6 *addr6;
- struct iface_info_ipv4 *p4;
- struct iface_info_ipv6 *p6;
+ struct smb_sockaddr_in *p4;
+ struct smb_sockaddr_in6 *p6;
struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
struct cifs_server_iface tmp_iface;
+ __be16 port;
ssize_t bytes_left;
size_t next = 0;
int nb_iface = 0;
@@ -631,13 +638,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
p = buf;
spin_lock(&ses->iface_lock);
- /* do not query too frequently, this time with lock held */
- if (ses->iface_last_update &&
- time_before(jiffies, ses->iface_last_update +
- (SMB_INTERFACE_POLL_INTERVAL * HZ))) {
- spin_unlock(&ses->iface_lock);
- return 0;
- }
/*
* Go through iface_list and mark them as inactive
@@ -660,10 +660,18 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
"Empty network interface list returned by server %s\n",
ses->server->hostname);
rc = -EOPNOTSUPP;
- ses->iface_last_update = jiffies;
goto out;
}
+ spin_lock(&ses->server->srv_lock);
+ if (ses->server->dstaddr.ss_family == AF_INET)
+ port = ((struct sockaddr_in *)&ses->server->dstaddr)->sin_port;
+ else if (ses->server->dstaddr.ss_family == AF_INET6)
+ port = ((struct sockaddr_in6 *)&ses->server->dstaddr)->sin6_port;
+ else
+ port = cpu_to_be16(CIFS_PORT);
+ spin_unlock(&ses->server->srv_lock);
+
while (bytes_left >= (ssize_t)sizeof(*p)) {
memset(&tmp_iface, 0, sizeof(tmp_iface));
/* default to 1Gbps when link speed is unset */
@@ -679,26 +687,26 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
*/
case INTERNETWORK:
addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
- p4 = (struct iface_info_ipv4 *)p->Buffer;
+ p4 = (struct smb_sockaddr_in *)p->Buffer;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
- addr4->sin_port = cpu_to_be16(CIFS_PORT);
+ addr4->sin_port = port;
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
&addr4->sin_addr);
break;
case INTERNETWORKV6:
addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr;
- p6 = (struct iface_info_ipv6 *)p->Buffer;
+ p6 = (struct smb_sockaddr_in6 *)p->Buffer;
addr6->sin6_family = AF_INET6;
memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
- addr6->sin6_port = cpu_to_be16(CIFS_PORT);
+ addr6->sin6_port = port;
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
&addr6->sin6_addr);
@@ -733,8 +741,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
spin_unlock(&ses->iface_lock);
/* no match. insert the entry in the list */
- info = kmalloc(sizeof(struct cifs_server_iface),
- GFP_KERNEL);
+ info = kmalloc_obj(struct cifs_server_iface);
if (!info) {
rc = -ENOMEM;
goto out;
@@ -766,6 +773,13 @@ next_iface:
bytes_left -= sizeof(*p);
break;
}
+ /* Validate that Next doesn't point beyond the buffer */
+ if (next > bytes_left) {
+ cifs_dbg(VFS, "%s: invalid Next pointer %zu > %zd\n",
+ __func__, next, bytes_left);
+ rc = -EINVAL;
+ goto out;
+ }
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
bytes_left -= next;
}
@@ -777,11 +791,11 @@ next_iface:
}
/* Azure rounds the buffer size up 8, to a 16 byte boundary */
- if ((bytes_left > 8) || p->Next)
+ if ((bytes_left > 8) ||
+ (bytes_left >= offsetof(struct network_interface_info_ioctl_rsp, Next)
+ + sizeof(p->Next) && p->Next))
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
- ses->iface_last_update = jiffies;
-
out:
/*
* Go through the list again and put the inactive entries
@@ -810,10 +824,17 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
struct TCP_Server_Info *pserver;
/* do not query too frequently */
+ spin_lock(&ses->iface_lock);
if (ses->iface_last_update &&
time_before(jiffies, ses->iface_last_update +
- (SMB_INTERFACE_POLL_INTERVAL * HZ)))
+ (SMB_INTERFACE_POLL_INTERVAL * HZ))) {
+ spin_unlock(&ses->iface_lock);
return 0;
+ }
+
+ ses->iface_last_update = jiffies;
+
+ spin_unlock(&ses->iface_lock);
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO,
@@ -939,11 +960,8 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, true, &cfid);
if (!rc) {
- if (cfid->has_lease) {
- close_cached_dir(cfid);
- return 0;
- }
close_cached_dir(cfid);
+ return 0;
}
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
@@ -978,7 +996,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
rc = -EREMOTE;
}
if (rc == -EREMOTE && IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS))
+ (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_DFS))
rc = -EOPNOTSUPP;
goto out;
}
@@ -1034,7 +1052,8 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
if (src_size < 8 + name_len + 1 + value_len) {
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_ea_overrun,
+ src_size, 8 + name_len + 1 + value_len);
goto out;
}
@@ -1171,10 +1190,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_file_full_ea_info *ea;
struct smb2_query_info_rsp *rsp;
int rc, used_len = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
+ used_len = 0;
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
@@ -1191,7 +1211,7 @@ replay_again:
ea = NULL;
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+ vars = kzalloc_obj(*vars);
if (!vars) {
rc = -ENOMEM;
goto out_free_path;
@@ -1301,6 +1321,9 @@ replay_again:
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
@@ -1447,6 +1470,8 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
+ lockdep_assert_held(&cinode->open_file_lock);
+
cfile->fid.persistent_fid = fid->persistent_fid;
cfile->fid.volatile_fid = fid->volatile_fid;
cfile->fid.access = fid->access;
@@ -1472,6 +1497,7 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
{
struct smb2_file_network_open_info file_inf;
struct inode *inode;
+ u64 asize;
int rc;
rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
@@ -1495,14 +1521,9 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
inode_set_atime_to_ts(inode,
cifs_NTtimeToUnix(file_inf.LastAccessTime));
- /*
- * i_blocks is not related to (i_size / i_blksize),
- * but instead 512 byte (2**9) size is required for
- * calculating num blocks.
- */
- if (le64_to_cpu(file_inf.AllocationSize) > 4096)
- inode->i_blocks =
- (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
+ asize = le64_to_cpu(file_inf.AllocationSize);
+ if (asize > 4096)
+ inode->i_blocks = CIFS_INO_BLOCKS(asize);
/* End of file and Attributes should not have to be updated on close */
spin_unlock(&inode->i_lock);
@@ -1512,11 +1533,11 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
static int
SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
- struct copychunk_ioctl *pcchunk)
+ struct copychunk_ioctl_req *pcchunk)
{
int rc;
unsigned int ret_data_len;
- struct resume_key_req *res_key;
+ struct resume_key_ioctl_rsp *res_key;
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */,
@@ -1529,7 +1550,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
goto req_res_key_exit;
}
- if (ret_data_len < sizeof(struct resume_key_req)) {
+ if (ret_data_len < sizeof(struct resume_key_ioctl_rsp)) {
cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n");
rc = -EINVAL;
goto req_res_key_exit;
@@ -1569,15 +1590,16 @@ smb2_ioctl_query_info(const unsigned int xid,
void *data[2];
int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
void (*free_req1_func)(struct smb_rqst *r);
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
+ buffer = NULL;
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
- vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
+ vars = kzalloc_obj(*vars, GFP_ATOMIC);
if (vars == NULL)
return -ENOMEM;
rqst = &vars->rqst[0];
@@ -1595,7 +1617,7 @@ replay_again:
}
if (!ses || !server) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_null_pointers);
goto free_vars;
}
@@ -1718,6 +1740,9 @@ replay_again:
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
@@ -1758,6 +1783,12 @@ replay_again:
qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length)
qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength);
+ if (qi.input_buffer_length > 0 &&
+ struct_size(qi_rsp, Buffer, qi.input_buffer_length) >
+ rsp_iov[1].iov_len) {
+ rc = -EFAULT;
+ goto out;
+ }
if (copy_to_user(&pqi->input_buffer_length,
&qi.input_buffer_length,
sizeof(qi.input_buffer_length))) {
@@ -1791,140 +1822,239 @@ free_vars:
return rc;
}
+/**
+ * calc_chunk_count - calculates the number chunks to be filled in the Chunks[]
+ * array of struct copychunk_ioctl
+ *
+ * @tcon: destination file tcon
+ * @bytes_left: how many bytes are left to copy
+ *
+ * Return: maximum number of chunks with which Chunks[] can be filled.
+ */
+static inline u32
+calc_chunk_count(struct cifs_tcon *tcon, u64 bytes_left)
+{
+ u32 max_chunks = READ_ONCE(tcon->max_chunks);
+ u32 max_bytes_copy = READ_ONCE(tcon->max_bytes_copy);
+ u32 max_bytes_chunk = READ_ONCE(tcon->max_bytes_chunk);
+ u64 need;
+ u32 allowed;
+
+ if (!max_bytes_chunk || !max_bytes_copy || !max_chunks)
+ return 0;
+
+ /* chunks needed for the remaining bytes */
+ need = DIV_ROUND_UP_ULL(bytes_left, max_bytes_chunk);
+ /* chunks allowed per cc request */
+ allowed = DIV_ROUND_UP(max_bytes_copy, max_bytes_chunk);
+
+ return (u32)umin(need, umin(max_chunks, allowed));
+}
+
+/**
+ * smb2_copychunk_range - server-side copy of data range
+ *
+ * @xid: transaction id
+ * @src_file: source file
+ * @dst_file: destination file
+ * @src_off: source file byte offset
+ * @len: number of bytes to copy
+ * @dst_off: destination file byte offset
+ *
+ * Obtains a resume key for @src_file and issues FSCTL_SRV_COPYCHUNK_WRITE
+ * IOCTLs, splitting the request into chunks limited by tcon->max_*.
+ *
+ * Return: @len on success; negative errno on failure.
+ */
static ssize_t
smb2_copychunk_range(const unsigned int xid,
- struct cifsFileInfo *srcfile,
- struct cifsFileInfo *trgtfile, u64 src_off,
- u64 len, u64 dest_off)
+ struct cifsFileInfo *src_file,
+ struct cifsFileInfo *dst_file,
+ u64 src_off,
+ u64 len,
+ u64 dst_off)
{
- int rc;
- unsigned int ret_data_len;
- struct copychunk_ioctl *pcchunk;
- struct copychunk_ioctl_rsp *retbuf = NULL;
+ int rc = 0;
+ unsigned int ret_data_len = 0;
+ struct copychunk_ioctl_req *cc_req = NULL;
+ struct copychunk_ioctl_rsp *cc_rsp = NULL;
struct cifs_tcon *tcon;
- int chunks_copied = 0;
- bool chunk_sizes_updated = false;
- ssize_t bytes_written, total_bytes_written = 0;
+ struct srv_copychunk *chunk;
+ u32 chunks, chunk_count, chunk_bytes;
+ u32 copy_bytes, copy_bytes_left;
+ u32 chunks_written, bytes_written;
+ u64 total_bytes_left = len;
+ u64 src_off_prev, dst_off_prev;
+ u32 retries = 0;
+
+ tcon = tlink_tcon(dst_file->tlink);
+
+ trace_smb3_copychunk_enter(xid, src_file->fid.volatile_fid,
+ dst_file->fid.volatile_fid, tcon->tid,
+ tcon->ses->Suid, src_off, dst_off, len);
+
+retry:
+ chunk_count = calc_chunk_count(tcon, total_bytes_left);
+ if (!chunk_count) {
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
- pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
- if (pcchunk == NULL)
- return -ENOMEM;
+ cc_req = kzalloc_flex(*cc_req, Chunks, chunk_count);
+ if (!cc_req) {
+ rc = -ENOMEM;
+ goto out;
+ }
- cifs_dbg(FYI, "%s: about to call request res key\n", __func__);
/* Request a key from the server to identify the source of the copy */
- rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
- srcfile->fid.persistent_fid,
- srcfile->fid.volatile_fid, pcchunk);
+ rc = SMB2_request_res_key(xid,
+ tlink_tcon(src_file->tlink),
+ src_file->fid.persistent_fid,
+ src_file->fid.volatile_fid,
+ cc_req);
- /* Note: request_res_key sets res_key null only if rc !=0 */
+ /* Note: request_res_key sets res_key null only if rc != 0 */
if (rc)
- goto cchunk_out;
+ goto out;
+
+ while (total_bytes_left > 0) {
+
+ /* Store previous offsets to allow rewind */
+ src_off_prev = src_off;
+ dst_off_prev = dst_off;
+
+ /*
+ * __counted_by_le(ChunkCount): set to allocated chunks before
+ * populating Chunks[]
+ */
+ cc_req->ChunkCount = cpu_to_le32(chunk_count);
+
+ chunks = 0;
+ copy_bytes = 0;
+ copy_bytes_left = umin(total_bytes_left, tcon->max_bytes_copy);
+ while (copy_bytes_left > 0 && chunks < chunk_count) {
+ chunk = &cc_req->Chunks[chunks++];
+
+ chunk->SourceOffset = cpu_to_le64(src_off);
+ chunk->TargetOffset = cpu_to_le64(dst_off);
- /* For now array only one chunk long, will make more flexible later */
- pcchunk->ChunkCount = cpu_to_le32(1);
- pcchunk->Reserved = 0;
- pcchunk->Reserved2 = 0;
+ chunk_bytes = umin(copy_bytes_left, tcon->max_bytes_chunk);
- tcon = tlink_tcon(trgtfile->tlink);
+ chunk->Length = cpu_to_le32(chunk_bytes);
+ /* Buffer is zeroed, no need to set chunk->Reserved = 0 */
- trace_smb3_copychunk_enter(xid, srcfile->fid.volatile_fid,
- trgtfile->fid.volatile_fid, tcon->tid,
- tcon->ses->Suid, src_off, dest_off, len);
+ src_off += chunk_bytes;
+ dst_off += chunk_bytes;
- while (len > 0) {
- pcchunk->SourceOffset = cpu_to_le64(src_off);
- pcchunk->TargetOffset = cpu_to_le64(dest_off);
- pcchunk->Length =
- cpu_to_le32(min_t(u64, len, tcon->max_bytes_chunk));
+ copy_bytes_left -= chunk_bytes;
+ copy_bytes += chunk_bytes;
+ }
+
+ cc_req->ChunkCount = cpu_to_le32(chunks);
+ /* Buffer is zeroed, no need to set cc_req->Reserved = 0 */
/* Request server copy to target from src identified by key */
- kfree(retbuf);
- retbuf = NULL;
- rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
- trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
- (char *)pcchunk, sizeof(struct copychunk_ioctl),
- CIFSMaxBufSize, (char **)&retbuf, &ret_data_len);
+ kfree(cc_rsp);
+ cc_rsp = NULL;
+ rc = SMB2_ioctl(xid, tcon, dst_file->fid.persistent_fid,
+ dst_file->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
+ (char *)cc_req, struct_size(cc_req, Chunks, chunks),
+ CIFSMaxBufSize, (char **)&cc_rsp, &ret_data_len);
+
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ if (unlikely(ret_data_len != sizeof(*cc_rsp))) {
+ cifs_tcon_dbg(VFS, "Copychunk invalid response: size %u/%zu\n",
+ ret_data_len, sizeof(*cc_rsp));
+ rc = smb_EIO1(smb_eio_trace_copychunk_inv_rsp, ret_data_len);
+ goto out;
+ }
+
+ bytes_written = le32_to_cpu(cc_rsp->TotalBytesWritten);
+ chunks_written = le32_to_cpu(cc_rsp->ChunksWritten);
+ chunk_bytes = le32_to_cpu(cc_rsp->ChunkBytesWritten);
+
if (rc == 0) {
- if (ret_data_len !=
- sizeof(struct copychunk_ioctl_rsp)) {
- cifs_tcon_dbg(VFS, "Invalid cchunk response size\n");
- rc = -EIO;
- goto cchunk_out;
- }
- if (retbuf->TotalBytesWritten == 0) {
- cifs_dbg(FYI, "no bytes copied\n");
- rc = -EIO;
- goto cchunk_out;
+ /* Check if server claimed to write more than we asked */
+ if (unlikely(!bytes_written || bytes_written > copy_bytes)) {
+ cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u\n",
+ bytes_written, copy_bytes);
+ rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_b,
+ bytes_written, copy_bytes);
+ goto out;
}
- /*
- * Check if server claimed to write more than we asked
- */
- if (le32_to_cpu(retbuf->TotalBytesWritten) >
- le32_to_cpu(pcchunk->Length)) {
- cifs_tcon_dbg(VFS, "Invalid copy chunk response\n");
- rc = -EIO;
- goto cchunk_out;
+ if (unlikely(!chunks_written || chunks_written > chunks)) {
+ cifs_tcon_dbg(VFS, "Copychunk invalid response: chunks written %u/%u\n",
+ chunks_written, chunks);
+ rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_c,
+ chunks_written, chunks);
+ goto out;
}
- if (le32_to_cpu(retbuf->ChunksWritten) != 1) {
- cifs_tcon_dbg(VFS, "Invalid num chunks written\n");
- rc = -EIO;
- goto cchunk_out;
+
+ /* Partial write: rewind */
+ if (bytes_written < copy_bytes) {
+ u32 delta = copy_bytes - bytes_written;
+
+ src_off -= delta;
+ dst_off -= delta;
}
- chunks_copied++;
-
- bytes_written = le32_to_cpu(retbuf->TotalBytesWritten);
- src_off += bytes_written;
- dest_off += bytes_written;
- len -= bytes_written;
- total_bytes_written += bytes_written;
-
- cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %zu\n",
- le32_to_cpu(retbuf->ChunksWritten),
- le32_to_cpu(retbuf->ChunkBytesWritten),
- bytes_written);
- trace_smb3_copychunk_done(xid, srcfile->fid.volatile_fid,
- trgtfile->fid.volatile_fid, tcon->tid,
- tcon->ses->Suid, src_off, dest_off, len);
- } else if (rc == -EINVAL) {
- if (ret_data_len != sizeof(struct copychunk_ioctl_rsp))
- goto cchunk_out;
-
- cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n",
- le32_to_cpu(retbuf->ChunksWritten),
- le32_to_cpu(retbuf->ChunkBytesWritten),
- le32_to_cpu(retbuf->TotalBytesWritten));
- /*
- * Check if this is the first request using these sizes,
- * (ie check if copy succeed once with original sizes
- * and check if the server gave us different sizes after
- * we already updated max sizes on previous request).
- * if not then why is the server returning an error now
- */
- if ((chunks_copied != 0) || chunk_sizes_updated)
- goto cchunk_out;
-
- /* Check that server is not asking us to grow size */
- if (le32_to_cpu(retbuf->ChunkBytesWritten) <
- tcon->max_bytes_chunk)
- tcon->max_bytes_chunk =
- le32_to_cpu(retbuf->ChunkBytesWritten);
- else
- goto cchunk_out; /* server gave us bogus size */
+ total_bytes_left -= bytes_written;
+ continue;
+ }
- /* No need to change MaxChunks since already set to 1 */
- chunk_sizes_updated = true;
- } else
- goto cchunk_out;
+ /*
+ * Check if server is not asking us to reduce size.
+ *
+ * Note: As per MS-SMB2 2.2.32.1, the values returned
+ * in cc_rsp are not strictly lower than what existed
+ * before.
+ */
+ if (bytes_written < tcon->max_bytes_copy) {
+ cifs_tcon_dbg(FYI, "Copychunk MaxBytesCopy updated: %u -> %u\n",
+ tcon->max_bytes_copy, bytes_written);
+ tcon->max_bytes_copy = bytes_written;
+ }
+
+ if (chunks_written < tcon->max_chunks) {
+ cifs_tcon_dbg(FYI, "Copychunk MaxChunks updated: %u -> %u\n",
+ tcon->max_chunks, chunks_written);
+ tcon->max_chunks = chunks_written;
+ }
+
+ if (chunk_bytes < tcon->max_bytes_chunk) {
+ cifs_tcon_dbg(FYI, "Copychunk MaxBytesChunk updated: %u -> %u\n",
+ tcon->max_bytes_chunk, chunk_bytes);
+ tcon->max_bytes_chunk = chunk_bytes;
+ }
+
+ /* reset to last offsets */
+ if (retries++ < 2) {
+ src_off = src_off_prev;
+ dst_off = dst_off_prev;
+ kfree(cc_req);
+ cc_req = NULL;
+ goto retry;
+ }
+
+ break;
}
-cchunk_out:
- kfree(pcchunk);
- kfree(retbuf);
- if (rc)
+out:
+ kfree(cc_req);
+ kfree(cc_rsp);
+ if (rc) {
+ trace_smb3_copychunk_err(xid, src_file->fid.volatile_fid,
+ dst_file->fid.volatile_fid, tcon->tid,
+ tcon->ses->Suid, src_off, dst_off, len, rc);
return rc;
- else
- return total_bytes_written;
+ } else {
+ trace_smb3_copychunk_done(xid, src_file->fid.volatile_fid,
+ dst_file->fid.volatile_fid, tcon->tid,
+ tcon->ses->Suid, src_off, dst_off, len);
+ return len;
+ }
}
static int
@@ -2076,14 +2206,6 @@ smb2_duplicate_extents(const unsigned int xid,
rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
if (rc)
goto duplicate_extents_out;
-
- /*
- * Although also could set plausible allocation size (i_blocks)
- * here in addition to setting the file size, in reflink
- * it is likely that the target file is sparse. Its allocation
- * size will be queried on next revalidate, but it is important
- * to make sure that file's cached size is updated immediately
- */
netfs_resize_file(netfs_inode(inode), dest_off + len, true);
cifs_setsize(inode, dest_off + len);
}
@@ -2334,7 +2456,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_query_directory_rsp *qd_rsp = NULL;
struct smb2_create_rsp *op_rsp = NULL;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -2392,6 +2514,9 @@ replay_again:
smb2_set_related(&rqst[1]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
}
@@ -2492,7 +2617,7 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
- trace_smb3_pend_credits(server->CurrentMid,
+ trace_smb3_pend_credits(server->current_mid,
server->conn_id, server->hostname, scredits,
le16_to_cpu(shdr->CreditRequest), in_flight);
cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n",
@@ -2566,16 +2691,19 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
return false;
}
-static int
-smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
- __u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode)
+static int smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
+ __u64 volatile_fid, __u16 net_fid,
+ struct cifsInodeInfo *cinode, unsigned int oplock)
{
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
+ __u8 op;
+
if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
return SMB2_lease_break(0, tcon, cinode->lease_key,
- smb2_get_lease_state(cinode));
+ smb2_get_lease_state(cinode, oplock));
- return SMB2_oplock_break(0, tcon, persistent_fid, volatile_fid,
- CIFS_CACHE_READ(cinode) ? 1 : 0);
+ op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE));
+ return SMB2_oplock_break(0, tcon, persistent_fid, volatile_fid, op);
}
void
@@ -2625,13 +2753,35 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
}
/* SMB headers in a compound are 8 byte aligned. */
- if (!IS_ALIGNED(len, 8)) {
- num_padding = 8 - (len & 7);
+ if (IS_ALIGNED(len, 8))
+ goto out;
+
+ num_padding = 8 - (len & 7);
+ if (smb3_encryption_required(tcon)) {
+ int i;
+
+ /*
+ * Flatten request into a single buffer with required padding as
+ * the encryption layer can't handle the padding iovs.
+ */
+ for (i = 1; i < rqst->rq_nvec; i++) {
+ memcpy(rqst->rq_iov[0].iov_base +
+ rqst->rq_iov[0].iov_len,
+ rqst->rq_iov[i].iov_base,
+ rqst->rq_iov[i].iov_len);
+ rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
+ }
+ memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
+ 0, num_padding);
+ rqst->rq_iov[0].iov_len += num_padding;
+ rqst->rq_nvec = 1;
+ } else {
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
rqst->rq_nvec++;
- len += num_padding;
}
+ len += num_padding;
+out:
shdr->NextCommand = cpu_to_le32(len);
}
@@ -2646,10 +2796,14 @@ bool smb2_should_replay(struct cifs_tcon *tcon,
return false;
if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
- msleep(*pcur_sleep);
- (*pcur_sleep) = ((*pcur_sleep) << 1);
- if ((*pcur_sleep) > CIFS_MAX_SLEEP)
- (*pcur_sleep) = CIFS_MAX_SLEEP;
+ /* Update sleep time for exponential backoff */
+ if (!(*pcur_sleep))
+ (*pcur_sleep) = 1;
+ else {
+ (*pcur_sleep) = ((*pcur_sleep) << 1);
+ if ((*pcur_sleep) > CIFS_MAX_SLEEP)
+ (*pcur_sleep) = CIFS_MAX_SLEEP;
+ }
return true;
}
@@ -2679,11 +2833,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid fid;
int rc;
__le16 *utf16_path;
- struct cached_fid *cfid = NULL;
- int retries = 0, cur_sleep = 1;
+ struct cached_fid *cfid;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
+ cfid = NULL;
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
@@ -2698,7 +2853,7 @@ replay_again:
flags |= CIFS_TRANSFORM_REQ;
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+ vars = kzalloc_obj(*vars);
if (!vars) {
rc = -ENOMEM;
goto out_free_path;
@@ -2769,6 +2924,9 @@ replay_again:
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
if (!cfid) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[2]);
@@ -2956,7 +3114,9 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
struct cifs_tcon,
tcon_list);
if (tcon) {
+ spin_lock(&tcon->tc_lock);
tcon->tc_count++;
+ spin_unlock(&tcon->tc_lock);
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_dfs_refer);
}
@@ -3006,7 +3166,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
}
if (!rc && !dfs_rsp)
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_dfsref_no_rsp);
if (rc) {
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
cifs_tcon_dbg(FYI, "%s: ioctl error: rc=%d\n", __func__, rc);
@@ -3025,13 +3185,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
out:
if (tcon && !tcon->ipc) {
/* ipc tcons are not refcounted */
- spin_lock(&cifs_tcp_ses_lock);
- tcon->tc_count--;
- trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
- netfs_trace_tcon_ref_dec_dfs_refer);
- /* tc_count can never go negative */
- WARN_ON(tcon->tc_count < 0);
- spin_unlock(&cifs_tcp_ses_lock);
+ cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_dfs_refer);
}
kfree(utf16_path);
kfree(dfs_req);
@@ -3092,8 +3246,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path) {
rc = -ENOMEM;
- free_xid(xid);
- return ERR_PTR(rc);
+ goto put_tlink;
}
oparms = (struct cifs_open_parms) {
@@ -3125,6 +3278,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
}
+put_tlink:
cifs_put_tlink(tlink);
free_xid(xid);
@@ -3165,8 +3319,7 @@ set_smb2_acl(struct smb_ntsd *pnntsd, __u32 acllen,
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path) {
rc = -ENOMEM;
- free_xid(xid);
- return rc;
+ goto put_tlink;
}
oparms = (struct cifs_open_parms) {
@@ -3187,6 +3340,7 @@ set_smb2_acl(struct smb_ntsd *pnntsd, __u32 acllen,
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
}
+put_tlink:
cifs_put_tlink(tlink);
free_xid(xid);
return rc;
@@ -3202,7 +3356,7 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL;
if (inode && !(info & SACL_SECINFO))
- open_file = find_readable_file(CIFS_I(inode), true);
+ open_file = find_readable_file(CIFS_I(inode), FIND_FSUID_ONLY);
if (!open_file || (info & SACL_SECINFO))
return get_smb2_acl_by_path(cifs_sb, path, pacllen, info);
@@ -3247,7 +3401,6 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
ses->Suid, offset, len);
- inode_lock(inode);
filemap_invalidate_lock(inode->i_mapping);
i_size = i_size_read(inode);
@@ -3265,6 +3418,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
* first, otherwise the data may be inconsistent with the server.
*/
truncate_pagecache_range(inode, offset, offset + len - 1);
+ netfs_wait_for_outstanding_io(inode);
/* if file not oplocked can't be sure whether asking to extend size */
rc = -EOPNOTSUPP;
@@ -3293,7 +3447,6 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
zero_range_exit:
filemap_invalidate_unlock(inode->i_mapping);
- inode_unlock(inode);
free_xid(xid);
if (rc)
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
@@ -3317,7 +3470,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
xid = get_xid();
- inode_lock(inode);
/* Need to make file sparse, if not already, before freeing range. */
/* Consider adding equivalent for compressed since it could also work */
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
@@ -3331,6 +3483,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
* caches first, otherwise the data may be inconsistent with the server.
*/
truncate_pagecache_range(inode, offset, offset + len - 1);
+ netfs_wait_for_outstanding_io(inode);
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
@@ -3365,7 +3518,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
unlock:
filemap_invalidate_unlock(inode->i_mapping);
out:
- inode_unlock(inode);
free_xid(xid);
return rc;
}
@@ -3629,8 +3781,6 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
xid = get_xid();
- inode_lock(inode);
-
old_eof = i_size_read(inode);
if ((off >= old_eof) ||
off + len >= old_eof) {
@@ -3645,6 +3795,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
truncate_pagecache_range(inode, off, old_eof);
ictx->zero_point = old_eof;
+ netfs_wait_for_outstanding_io(inode);
rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
old_eof - off - len, off);
@@ -3665,8 +3816,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
fscache_resize_cookie(cifs_inode_cookie(inode), new_eof);
out_2:
filemap_invalidate_unlock(inode->i_mapping);
- out:
- inode_unlock(inode);
+out:
free_xid(xid);
return rc;
}
@@ -3683,8 +3833,6 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
xid = get_xid();
- inode_lock(inode);
-
old_eof = i_size_read(inode);
if (off >= old_eof) {
rc = -EINVAL;
@@ -3699,6 +3847,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
if (rc < 0)
goto out_2;
truncate_pagecache_range(inode, off, old_eof);
+ netfs_wait_for_outstanding_io(inode);
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, cfile->pid, new_eof);
@@ -3721,8 +3870,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
rc = 0;
out_2:
filemap_invalidate_unlock(inode->i_mapping);
- out:
- inode_unlock(inode);
+out:
free_xid(xid);
return rc;
}
@@ -3754,7 +3902,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
* some servers (Windows2016) will not reflect recent writes in
* QUERY_ALLOCATED_RANGES until SMB2_flush is called.
*/
- wrcfile = find_writable_file(cifsi, FIND_WR_ANY);
+ wrcfile = find_writable_file(cifsi, FIND_ANY);
if (wrcfile) {
filemap_write_and_wait(inode->i_mapping);
smb2_flush_file(xid, tcon, &wrcfile->fid);
@@ -3913,6 +4061,7 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server,
struct cifsInodeInfo *cinode, __u32 oplock,
__u16 epoch, bool *purge_cache)
{
+ lockdep_assert_held(&cinode->open_file_lock);
server->ops->set_oplock_level(cinode, oplock, 0, NULL);
}
@@ -3953,19 +4102,19 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
return;
if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
- cinode->oplock = CIFS_CACHE_RHW_FLG;
+ WRITE_ONCE(cinode->oplock, CIFS_CACHE_RHW_FLG);
cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
&cinode->netfs.inode);
} else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
- cinode->oplock = CIFS_CACHE_RW_FLG;
+ WRITE_ONCE(cinode->oplock, CIFS_CACHE_RW_FLG);
cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
&cinode->netfs.inode);
} else if (oplock == SMB2_OPLOCK_LEVEL_II) {
- cinode->oplock = CIFS_CACHE_READ_FLG;
+ WRITE_ONCE(cinode->oplock, CIFS_CACHE_READ_FLG);
cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
&cinode->netfs.inode);
} else
- cinode->oplock = 0;
+ WRITE_ONCE(cinode->oplock, 0);
}
static void
@@ -4000,7 +4149,7 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
if (!new_oplock)
strscpy(message, "None");
- cinode->oplock = new_oplock;
+ WRITE_ONCE(cinode->oplock, new_oplock);
cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
&cinode->netfs.inode);
}
@@ -4009,30 +4158,32 @@ static void
smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
__u16 epoch, bool *purge_cache)
{
- unsigned int old_oplock = cinode->oplock;
+ unsigned int old_oplock = READ_ONCE(cinode->oplock);
+ unsigned int new_oplock;
smb21_set_oplock_level(cinode, oplock, epoch, purge_cache);
+ new_oplock = READ_ONCE(cinode->oplock);
if (purge_cache) {
*purge_cache = false;
if (old_oplock == CIFS_CACHE_READ_FLG) {
- if (cinode->oplock == CIFS_CACHE_READ_FLG &&
+ if (new_oplock == CIFS_CACHE_READ_FLG &&
(epoch - cinode->epoch > 0))
*purge_cache = true;
- else if (cinode->oplock == CIFS_CACHE_RH_FLG &&
+ else if (new_oplock == CIFS_CACHE_RH_FLG &&
(epoch - cinode->epoch > 1))
*purge_cache = true;
- else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
+ else if (new_oplock == CIFS_CACHE_RHW_FLG &&
(epoch - cinode->epoch > 1))
*purge_cache = true;
- else if (cinode->oplock == 0 &&
+ else if (new_oplock == 0 &&
(epoch - cinode->epoch > 0))
*purge_cache = true;
} else if (old_oplock == CIFS_CACHE_RH_FLG) {
- if (cinode->oplock == CIFS_CACHE_RH_FLG &&
+ if (new_oplock == CIFS_CACHE_RH_FLG &&
(epoch - cinode->epoch > 0))
*purge_cache = true;
- else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
+ else if (new_oplock == CIFS_CACHE_RHW_FLG &&
(epoch - cinode->epoch > 1))
*purge_cache = true;
}
@@ -4069,11 +4220,11 @@ map_oplock_to_lease(u8 oplock)
}
static char *
-smb2_create_lease_buf(u8 *lease_key, u8 oplock)
+smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
{
struct create_lease *buf;
- buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL);
+ buf = kzalloc_obj(struct create_lease);
if (!buf)
return NULL;
@@ -4095,16 +4246,19 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock)
}
static char *
-smb3_create_lease_buf(u8 *lease_key, u8 oplock)
+smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
{
struct create_lease_v2 *buf;
- buf = kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL);
+ buf = kzalloc_obj(struct create_lease_v2);
if (!buf)
return NULL;
memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
+ buf->lcontext.LeaseFlags = flags;
+ if (flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
+ memcpy(&buf->lcontext.ParentLeaseKey, parent_lease_key, SMB2_LEASE_KEY_SIZE);
buf->ccontext.DataOffset = cpu_to_le16(offsetof
(struct create_lease_v2, lcontext));
@@ -4179,7 +4333,7 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
int num_rqst, const u8 *sig, u8 **iv,
struct aead_request **req, struct sg_table *sgt,
- unsigned int *num_sgs, size_t *sensitive_size)
+ unsigned int *num_sgs)
{
unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
unsigned int iv_size = crypto_aead_ivsize(tfm);
@@ -4196,9 +4350,8 @@ static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst
len += req_size;
len = ALIGN(len, __alignof__(struct scatterlist));
len += array_size(*num_sgs, sizeof(struct scatterlist));
- *sensitive_size = len;
- p = kvzalloc(len, GFP_NOFS);
+ p = kzalloc(len, GFP_NOFS);
if (!p)
return ERR_PTR(-ENOMEM);
@@ -4212,16 +4365,14 @@ static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst
static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *rqst,
int num_rqst, const u8 *sig, u8 **iv,
- struct aead_request **req, struct scatterlist **sgl,
- size_t *sensitive_size)
+ struct aead_request **req, struct scatterlist **sgl)
{
struct sg_table sgtable = {};
unsigned int skip, num_sgs, i, j;
ssize_t rc;
void *p;
- p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable,
- &num_sgs, sensitive_size);
+ p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable, &num_sgs);
if (IS_ERR(p))
return ERR_CAST(p);
@@ -4307,9 +4458,9 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
u8 key[SMB3_ENC_DEC_KEY_SIZE];
struct aead_request *req;
u8 *iv;
+ DECLARE_CRYPTO_WAIT(wait);
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
void *creq;
- size_t sensitive_size;
rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
if (rc) {
@@ -4335,8 +4486,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
return rc;
}
- creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg,
- &sensitive_size);
+ creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg);
if (IS_ERR(creq))
return PTR_ERR(creq);
@@ -4357,71 +4507,20 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
aead_request_set_crypt(req, sg, sg, crypt_len, iv);
aead_request_set_ad(req, assoc_data_len);
- rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
+ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &wait);
+
+ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req)
+ : crypto_aead_decrypt(req), &wait);
if (!rc && enc)
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
- kvfree_sensitive(creq, sensitive_size);
+ kfree_sensitive(creq);
return rc;
}
/*
- * Clear a read buffer, discarding the folios which have the 1st mark set.
- */
-static void cifs_clear_folioq_buffer(struct folio_queue *buffer)
-{
- struct folio_queue *folioq;
-
- while ((folioq = buffer)) {
- for (int s = 0; s < folioq_count(folioq); s++)
- if (folioq_is_marked(folioq, s))
- folio_put(folioq_folio(folioq, s));
- buffer = folioq->next;
- kfree(folioq);
- }
-}
-
-/*
- * Allocate buffer space into a folio queue.
- */
-static struct folio_queue *cifs_alloc_folioq_buffer(ssize_t size)
-{
- struct folio_queue *buffer = NULL, *tail = NULL, *p;
- struct folio *folio;
- unsigned int slot;
-
- do {
- if (!tail || folioq_full(tail)) {
- p = kmalloc(sizeof(*p), GFP_NOFS);
- if (!p)
- goto nomem;
- folioq_init(p, 0);
- if (tail) {
- tail->next = p;
- p->prev = tail;
- } else {
- buffer = p;
- }
- tail = p;
- }
-
- folio = folio_alloc(GFP_KERNEL|__GFP_HIGHMEM, 0);
- if (!folio)
- goto nomem;
-
- slot = folioq_append_mark(tail, folio);
- size -= folioq_folio_size(tail, slot);
- } while (size > 0);
-
- return buffer;
-
-nomem:
- cifs_clear_folioq_buffer(buffer);
- return NULL;
-}
-
-/*
* Copy data from an iterator to the folios in a folio queue buffer.
*/
static bool cifs_copy_iter_to_folioq(struct iov_iter *iter, size_t size,
@@ -4446,7 +4545,7 @@ void
smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst)
{
for (int i = 0; i < num_rqst; i++)
- cifs_clear_folioq_buffer(rqst[i].rq_buffer);
+ netfs_free_folioq_buffer(rqst[i].rq_buffer);
}
/*
@@ -4473,7 +4572,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
for (int i = 1; i < num_rqst; i++) {
struct smb_rqst *old = &old_rq[i - 1];
struct smb_rqst *new = &new_rq[i];
- struct folio_queue *buffer;
+ struct folio_queue *buffer = NULL;
size_t size = iov_iter_count(&old->rq_iter);
orig_len += smb_rqst_len(server, old);
@@ -4481,8 +4580,10 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
new->rq_nvec = old->rq_nvec;
if (size > 0) {
- buffer = cifs_alloc_folioq_buffer(size);
- if (!buffer)
+ size_t cur_size = 0;
+ rc = netfs_alloc_folioq_buffer(NULL, &buffer, &cur_size,
+ size, GFP_NOFS);
+ if (rc < 0)
goto err_free;
new->rq_buffer = buffer;
@@ -4490,7 +4591,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
buffer, 0, 0, size);
if (!cifs_copy_iter_to_folioq(&old->rq_iter, size, buffer)) {
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_tx_copy_iter_to_buf, size);
goto err_free;
}
}
@@ -4591,7 +4692,8 @@ cifs_copy_folioq_to_iter(struct folio_queue *folioq, size_t data_size,
n = copy_folio_to_iter(folio, skip, len, iter);
if (n != len) {
cifs_dbg(VFS, "%s: something went wrong\n", __func__);
- return -EIO;
+ return smb_EIO2(smb_eio_trace_rx_copy_to_iter,
+ n, len);
}
data_size -= n;
skip = 0;
@@ -4613,7 +4715,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
unsigned int pad_len;
struct cifs_io_subrequest *rdata = mid->callback_data;
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
- int length;
+ size_t copied;
bool use_rdma_mr = false;
if (shdr->Command != SMB2_READ) {
@@ -4651,7 +4753,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (is_offloaded)
mid->mid_state = MID_RESPONSE_RECEIVED;
else
- dequeue_mid(mid, false);
+ dequeue_mid(server, mid, false);
return 0;
}
@@ -4674,11 +4776,11 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
/* data_offset is beyond the end of smallbuf */
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
__func__, data_offset);
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_overlong, data_offset);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
- dequeue_mid(mid, rdata->result);
+ dequeue_mid(server, mid, rdata->result);
return 0;
}
@@ -4693,21 +4795,21 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
/* data offset is beyond the 1st page of response */
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
__func__, data_offset);
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_overpage, data_offset);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
- dequeue_mid(mid, rdata->result);
+ dequeue_mid(server, mid, rdata->result);
return 0;
}
if (data_len > buffer_len - pad_len) {
/* data_len is corrupt -- discard frame */
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_bad_datalen, data_len);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
- dequeue_mid(mid, rdata->result);
+ dequeue_mid(server, mid, rdata->result);
return 0;
}
@@ -4718,7 +4820,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
- dequeue_mid(mid, rdata->result);
+ dequeue_mid(server, mid, rdata->result);
return 0;
}
rdata->got_bytes = buffer_len;
@@ -4726,25 +4828,25 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
} else if (buf_len >= data_offset + data_len) {
/* read response payload is in buf */
WARN_ONCE(buffer, "read data can be either in buf or in buffer");
- length = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
- if (length < 0)
- return length;
- rdata->got_bytes = data_len;
+ copied = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
+ if (copied == 0)
+ return smb_EIO2(smb_eio_trace_rx_copy_to_iter, copied, data_len);
+ rdata->got_bytes = copied;
} else {
/* read response payload cannot be in both buf and pages */
WARN_ONCE(1, "buf can not contain only a part of read data");
- rdata->result = -EIO;
+ rdata->result = smb_EIO(smb_eio_trace_rx_both_buf);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
- dequeue_mid(mid, rdata->result);
+ dequeue_mid(server, mid, rdata->result);
return 0;
}
if (is_offloaded)
mid->mid_state = MID_RESPONSE_RECEIVED;
else
- dequeue_mid(mid, false);
+ dequeue_mid(server, mid, false);
return 0;
}
@@ -4791,30 +4893,30 @@ static void smb2_decrypt_offload(struct work_struct *work)
dw->server->ops->is_network_name_deleted(dw->buf,
dw->server);
- mid->callback(mid);
+ mid_execute_callback(dw->server, mid);
} else {
spin_lock(&dw->server->srv_lock);
if (dw->server->tcpStatus == CifsNeedReconnect) {
- spin_lock(&dw->server->mid_lock);
+ spin_lock(&dw->server->mid_queue_lock);
mid->mid_state = MID_RETRY_NEEDED;
- spin_unlock(&dw->server->mid_lock);
+ spin_unlock(&dw->server->mid_queue_lock);
spin_unlock(&dw->server->srv_lock);
- mid->callback(mid);
+ mid_execute_callback(dw->server, mid);
} else {
- spin_lock(&dw->server->mid_lock);
+ spin_lock(&dw->server->mid_queue_lock);
mid->mid_state = MID_REQUEST_SUBMITTED;
- mid->mid_flags &= ~(MID_DELETED);
+ mid->deleted_from_q = false;
list_add_tail(&mid->qhead,
&dw->server->pending_mid_q);
- spin_unlock(&dw->server->mid_lock);
+ spin_unlock(&dw->server->mid_queue_lock);
spin_unlock(&dw->server->srv_lock);
}
}
- release_mid(mid);
+ release_mid(dw->server, mid);
}
free_pages:
- cifs_clear_folioq_buffer(dw->buffer);
+ netfs_free_folioq_buffer(dw->buffer);
cifs_small_buf_release(dw->buf);
kfree(dw);
}
@@ -4832,7 +4934,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
int rc;
struct smb2_decrypt_work *dw;
- dw = kzalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL);
+ dw = kzalloc_obj(struct smb2_decrypt_work);
if (!dw)
return -ENOMEM;
INIT_WORK(&dw->decrypt, smb2_decrypt_offload);
@@ -4847,14 +4949,22 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
goto free_dw;
server->total_read += rc;
+ if (le32_to_cpu(tr_hdr->OriginalMessageSize) <
+ server->vals->read_rsp_size) {
+ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n",
+ le32_to_cpu(tr_hdr->OriginalMessageSize),
+ server->vals->read_rsp_size);
+ rc = -EINVAL;
+ goto discard_data;
+ }
len = le32_to_cpu(tr_hdr->OriginalMessageSize) -
server->vals->read_rsp_size;
dw->len = len;
len = round_up(dw->len, PAGE_SIZE);
- rc = -ENOMEM;
- dw->buffer = cifs_alloc_folioq_buffer(len);
- if (!dw->buffer)
+ size_t cur_size = 0;
+ rc = netfs_alloc_folioq_buffer(NULL, &dw->buffer, &cur_size, len, GFP_NOFS);
+ if (rc < 0)
goto discard_data;
iov_iter_folio_queue(&iter, ITER_DEST, dw->buffer, 0, 0, len);
@@ -4915,7 +5025,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
}
free_pages:
- cifs_clear_folioq_buffer(dw->buffer);
+ netfs_free_folioq_buffer(dw->buffer);
free_dw:
kfree(dw);
return rc;
@@ -5234,7 +5344,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, umode_t mode, dev_t dev)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
int rc = -EOPNOTSUPP;
/*
@@ -5243,12 +5353,12 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
* supports block and char device, socket & fifo,
* and was used by default in earlier versions of Windows
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ if (sbflags & CIFS_MOUNT_UNX_EMUL) {
rc = cifs_sfu_make_node(xid, inode, dentry, tcon,
full_path, mode, dev);
- } else if (le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS) {
- rc = smb2_mknod_reparse(xid, inode, dentry, tcon,
- full_path, mode, dev);
+ } else if (CIFS_REPARSE_SUPPORT(tcon)) {
+ rc = mknod_reparse(xid, inode, dentry, tcon,
+ full_path, mode, dev);
}
return rc;
}
@@ -5306,7 +5416,7 @@ struct smb_version_operations smb20_operations = {
.get_reparse_point_buffer = smb2_get_reparse_point_buffer,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
- .create_reparse_symlink = smb2_create_reparse_symlink,
+ .create_reparse_inode = smb2_create_reparse_inode,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
@@ -5329,7 +5439,6 @@ struct smb_version_operations smb20_operations = {
.get_lease_key = smb2_get_lease_key,
.set_lease_key = smb2_set_lease_key,
.new_lease_key = smb2_new_lease_key,
- .calc_signature = smb2_calc_signature,
.is_read_op = smb2_is_read_op,
.set_oplock_level = smb2_set_oplock_level,
.create_lease_buf = smb2_create_lease_buf,
@@ -5353,6 +5462,7 @@ struct smb_version_operations smb20_operations = {
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
+ .rename_pending_delete = smb2_rename_pending_delete,
};
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
@@ -5409,7 +5519,7 @@ struct smb_version_operations smb21_operations = {
.get_reparse_point_buffer = smb2_get_reparse_point_buffer,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
- .create_reparse_symlink = smb2_create_reparse_symlink,
+ .create_reparse_inode = smb2_create_reparse_inode,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
@@ -5432,7 +5542,6 @@ struct smb_version_operations smb21_operations = {
.get_lease_key = smb2_get_lease_key,
.set_lease_key = smb2_set_lease_key,
.new_lease_key = smb2_new_lease_key,
- .calc_signature = smb2_calc_signature,
.is_read_op = smb21_is_read_op,
.set_oplock_level = smb21_set_oplock_level,
.create_lease_buf = smb2_create_lease_buf,
@@ -5458,6 +5567,7 @@ struct smb_version_operations smb21_operations = {
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
+ .rename_pending_delete = smb2_rename_pending_delete,
};
struct smb_version_operations smb30_operations = {
@@ -5516,7 +5626,7 @@ struct smb_version_operations smb30_operations = {
.get_reparse_point_buffer = smb2_get_reparse_point_buffer,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
- .create_reparse_symlink = smb2_create_reparse_symlink,
+ .create_reparse_inode = smb2_create_reparse_inode,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
@@ -5541,7 +5651,6 @@ struct smb_version_operations smb30_operations = {
.set_lease_key = smb2_set_lease_key,
.new_lease_key = smb2_new_lease_key,
.generate_signingkey = generate_smb30signingkey,
- .calc_signature = smb3_calc_signature,
.set_integrity = smb3_set_integrity,
.is_read_op = smb21_is_read_op,
.set_oplock_level = smb3_set_oplock_level,
@@ -5574,6 +5683,7 @@ struct smb_version_operations smb30_operations = {
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
+ .rename_pending_delete = smb2_rename_pending_delete,
};
struct smb_version_operations smb311_operations = {
@@ -5632,7 +5742,7 @@ struct smb_version_operations smb311_operations = {
.get_reparse_point_buffer = smb2_get_reparse_point_buffer,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
- .create_reparse_symlink = smb2_create_reparse_symlink,
+ .create_reparse_inode = smb2_create_reparse_inode,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
@@ -5657,7 +5767,6 @@ struct smb_version_operations smb311_operations = {
.set_lease_key = smb2_set_lease_key,
.new_lease_key = smb2_new_lease_key,
.generate_signingkey = generate_smb311signingkey,
- .calc_signature = smb3_calc_signature,
.set_integrity = smb3_set_integrity,
.is_read_op = smb21_is_read_op,
.set_oplock_level = smb3_set_oplock_level,
@@ -5690,6 +5799,7 @@ struct smb_version_operations smb311_operations = {
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
+ .rename_pending_delete = smb2_rename_pending_delete,
};
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -5702,7 +5812,6 @@ struct smb_version_values smb20_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5724,7 +5833,6 @@ struct smb_version_values smb21_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5745,7 +5853,6 @@ struct smb_version_values smb3any_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5766,7 +5873,6 @@ struct smb_version_values smbdefault_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5787,7 +5893,6 @@ struct smb_version_values smb30_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5808,7 +5913,6 @@ struct smb_version_values smb302_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
@@ -5829,7 +5933,6 @@ struct smb_version_values smb311_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
- .header_preamble_size = 0,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp),
.lock_cmd = SMB2_LOCK,
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index c4d52bebd37d..cb61051f9af3 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -26,15 +26,15 @@
#include <linux/netfs.h>
#include <trace/events/netfs.h>
#include "cifsglob.h"
-#include "cifsacl.h"
#include "cifsproto.h"
+#include "cifsacl.h"
#include "smb2proto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "ntlmssp.h"
+#include "../common/smbfsctl.h"
#include "../common/smb2status.h"
#include "smb2glob.h"
-#include "cifspdu.h"
#include "cifs_spnego.h"
#include "smbdirect.h"
#include "trace.h"
@@ -167,7 +167,7 @@ out:
static int
cifs_chan_skip_or_disable(struct cifs_ses *ses,
struct TCP_Server_Info *server,
- bool from_reconnect)
+ bool from_reconnect, bool disable_mchan)
{
struct TCP_Server_Info *pserver;
unsigned int chan_index;
@@ -205,14 +205,46 @@ skip_terminate:
return -EHOSTDOWN;
}
- cifs_server_dbg(VFS,
- "server does not support multichannel anymore. Disable all other channels\n");
- cifs_disable_secondary_channels(ses);
-
+ cifs_decrease_secondary_channels(ses, disable_mchan);
return 0;
}
+/*
+ * smb3_update_ses_channels - Synchronize session channels with new configuration
+ * @ses: pointer to the CIFS session structure
+ * @server: pointer to the TCP server info structure
+ * @from_reconnect: indicates if called from reconnect context
+ * @disable_mchan: indicates if called from reconnect to disable multichannel
+ *
+ * Returns 0 on success or error code on failure.
+ *
+ * Outside of reconfigure, this function is called from cifs_mount() during mount
+ * and from reconnect scenarios to adjust channel count when the
+ * server's multichannel support changes.
+ */
+int smb3_update_ses_channels(struct cifs_ses *ses, struct TCP_Server_Info *server,
+ bool from_reconnect, bool disable_mchan)
+{
+ int rc = 0;
+ /*
+ * Manage session channels based on current count vs max:
+ * - If disable requested, skip or disable the channel
+ * - If below max channels, attempt to add more
+ * - If above max channels, skip or disable excess channels
+ */
+ if (disable_mchan)
+ rc = cifs_chan_skip_or_disable(ses, server, from_reconnect, disable_mchan);
+ else {
+ if (ses->chan_count < ses->chan_max)
+ rc = cifs_try_adding_channels(ses);
+ else if (ses->chan_count > ses->chan_max)
+ rc = cifs_chan_skip_or_disable(ses, server, from_reconnect, disable_mchan);
+ }
+
+ return rc;
+}
+
static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct TCP_Server_Info *server, bool from_reconnect)
@@ -239,8 +271,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
*/
if (smb2_command != SMB2_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock);
- cifs_dbg(FYI, "can not send cmd %d while umounting\n",
- smb2_command);
+ cifs_tcon_dbg(FYI, "can not send cmd %d while umounting\n",
+ smb2_command);
return -ENODEV;
}
}
@@ -248,15 +280,15 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
ses = tcon->ses;
if (!ses)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
spin_lock(&ses->ses_lock);
if (ses->ses_status == SES_EXITING) {
spin_unlock(&ses->ses_lock);
- return -EIO;
+ return smb_EIO(smb_eio_trace_sess_exiting);
}
spin_unlock(&ses->ses_lock);
if (!ses->server || !server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsNeedReconnect) {
@@ -295,9 +327,9 @@ again:
return 0;
}
spin_unlock(&ses->chan_lock);
- cifs_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d",
- tcon->ses->chans_need_reconnect,
- tcon->need_reconnect);
+ cifs_tcon_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d\n",
+ tcon->ses->chans_need_reconnect,
+ tcon->need_reconnect);
mutex_lock(&ses->session_mutex);
/*
@@ -354,8 +386,8 @@ again:
*/
if (ses->chan_count > 1 &&
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
- rc = cifs_chan_skip_or_disable(ses, server,
- from_reconnect);
+ rc = smb3_update_ses_channels(ses, server,
+ from_reconnect, true /* disable_mchan */);
if (rc) {
mutex_unlock(&ses->session_mutex);
goto out;
@@ -391,11 +423,11 @@ skip_sess_setup:
rc = cifs_tree_connect(0, tcon);
- cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
+ cifs_tcon_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) {
/* If sess reconnected but tcon didn't, something strange ... */
mutex_unlock(&ses->session_mutex);
- cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
+ cifs_tcon_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
goto out;
}
@@ -411,14 +443,23 @@ skip_sess_setup:
if (!rc &&
(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) &&
server->ops->query_server_interfaces) {
- mutex_unlock(&ses->session_mutex);
-
/*
- * query server network interfaces, in case they change
+ * query server network interfaces, in case they change.
+ * Also mark the session as pending this update while the query
+ * is in progress. This will be used to avoid calling
+ * smb2_reconnect recursively.
*/
+ ses->flags |= CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES;
xid = get_xid();
rc = server->ops->query_server_interfaces(xid, tcon, false);
free_xid(xid);
+ ses->flags &= ~CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES;
+
+ if (!tcon->ipc && !tcon->dummy)
+ queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
+ (SMB_INTERFACE_POLL_INTERVAL * HZ));
+
+ mutex_unlock(&ses->session_mutex);
if (rc == -EOPNOTSUPP && ses->chan_count > 1) {
/*
@@ -428,23 +469,22 @@ skip_sess_setup:
* treat this as server not supporting multichannel
*/
- rc = cifs_chan_skip_or_disable(ses, server,
- from_reconnect);
+ rc = smb3_update_ses_channels(ses, server,
+ from_reconnect,
+ true /* disable_mchan */);
goto skip_add_channels;
} else if (rc)
- cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
- __func__, rc);
+ cifs_tcon_dbg(FYI, "%s: failed to query server interfaces: %d\n",
+ __func__, rc);
if (ses->chan_max > ses->chan_count &&
ses->iface_count &&
!SERVER_IS_CHAN(server)) {
- if (ses->chan_count == 1) {
+ if (ses->chan_count == 1)
cifs_server_dbg(VFS, "supports multichannel now\n");
- queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
- (SMB_INTERFACE_POLL_INTERVAL * HZ));
- }
- cifs_try_adding_channels(ses);
+ smb3_update_ses_channels(ses, server, from_reconnect,
+ false /* disable_mchan */);
}
} else {
mutex_unlock(&ses->session_mutex);
@@ -456,7 +496,7 @@ skip_add_channels:
spin_unlock(&ses->ses_lock);
if (smb2_command != SMB2_INTERNAL_CMD)
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ cifs_queue_server_reconn(server);
atomic_inc(&tconInfoReconnectCount);
out:
@@ -560,11 +600,18 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
struct TCP_Server_Info *server,
void **request_buf, unsigned int *total_len)
{
- /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */
- if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) {
+ /*
+ * Skip reconnect in one of the following cases:
+ * 1. For FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs
+ * 2. For FSCTL_QUERY_NETWORK_INTERFACE_INFO IOCTL when called from
+ * smb2_reconnect (indicated by CIFS_SES_FLAG_SCALE_CHANNELS ses flag)
+ */
+ if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO ||
+ (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO &&
+ (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES)))
return __smb2_plain_req_init(SMB2_IOCTL, tcon, server,
request_buf, total_len);
- }
+
return smb2_plain_req_init(SMB2_IOCTL, tcon, server,
request_buf, total_len);
}
@@ -961,8 +1008,7 @@ create_posix_buf(umode_t mode)
{
struct create_posix *buf;
- buf = kzalloc(sizeof(struct create_posix),
- GFP_KERNEL);
+ buf = kzalloc_obj(struct create_posix);
if (!buf)
return NULL;
@@ -1047,7 +1093,7 @@ SMB2_negotiate(const unsigned int xid,
if (!server) {
WARN(1, "%s: server is NULL!\n", __func__);
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
}
rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
@@ -1091,8 +1137,7 @@ SMB2_negotiate(const unsigned int xid,
req->SecurityMode = 0;
req->Capabilities = cpu_to_le32(server->vals->req_capabilities);
- if (ses->chan_max > 1)
- req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
+ req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
/* ClientGUID must be zero for SMB2.02 dialect */
if (server->vals->protocol_id == SMB20_PROT_ID)
@@ -1128,64 +1173,84 @@ SMB2_negotiate(const unsigned int xid,
} else if (rc != 0)
goto neg_exit;
- rc = -EIO;
+ u16 dialect = le16_to_cpu(rsp->DialectRevision);
if (strcmp(server->vals->version_string,
SMB3ANY_VERSION_STRING) == 0) {
- if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
+ switch (dialect) {
+ case SMB20_PROT_ID:
cifs_server_dbg(VFS,
"SMB2 dialect returned but not requested\n");
+ rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 3);
goto neg_exit;
- } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
+ case SMB21_PROT_ID:
cifs_server_dbg(VFS,
"SMB2.1 dialect returned but not requested\n");
+ rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 3);
goto neg_exit;
- } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+ case SMB311_PROT_ID:
/* ops set to 3.0 by default for default so update */
server->ops = &smb311_operations;
server->vals = &smb311_values;
+ break;
+ default:
+ break;
}
} else if (strcmp(server->vals->version_string,
- SMBDEFAULT_VERSION_STRING) == 0) {
- if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
+ SMBDEFAULT_VERSION_STRING) == 0) {
+ switch (dialect) {
+ case SMB20_PROT_ID:
cifs_server_dbg(VFS,
"SMB2 dialect returned but not requested\n");
+ rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 0);
goto neg_exit;
- } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
+ case SMB21_PROT_ID:
/* ops set to 3.0 by default for default so update */
server->ops = &smb21_operations;
server->vals = &smb21_values;
- } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+ break;
+ case SMB311_PROT_ID:
server->ops = &smb311_operations;
server->vals = &smb311_values;
+ break;
+ default:
+ break;
}
- } else if (le16_to_cpu(rsp->DialectRevision) !=
- server->vals->protocol_id) {
+ } else if (dialect != server->vals->protocol_id) {
/* if requested single dialect ensure returned dialect matched */
cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
- le16_to_cpu(rsp->DialectRevision));
+ dialect);
+ rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect,
+ dialect, server->vals->protocol_id);
goto neg_exit;
}
cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);
- if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID))
+ switch (dialect) {
+ case SMB20_PROT_ID:
cifs_dbg(FYI, "negotiated smb2.0 dialect\n");
- else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID))
+ break;
+ case SMB21_PROT_ID:
cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
- else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
+ break;
+ case SMB30_PROT_ID:
cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
- else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
+ break;
+ case SMB302_PROT_ID:
cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
- else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
+ break;
+ case SMB311_PROT_ID:
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
- else {
+ break;
+ default:
cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n",
- le16_to_cpu(rsp->DialectRevision));
+ dialect);
+ rc = smb_EIO1(smb_eio_trace_neg_inval_dialect, dialect);
goto neg_exit;
}
rc = 0;
- server->dialect = le16_to_cpu(rsp->DialectRevision);
+ server->dialect = dialect;
/*
* Keep a copy of the hash after negprot. This hash will be
@@ -1241,10 +1306,10 @@ SMB2_negotiate(const unsigned int xid,
if (rc == 1)
rc = 0;
else if (rc == 0)
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_neg_decode_token, rc);
}
- if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+ if (server->dialect == SMB311_PROT_ID) {
if (rsp->NegotiateContextCount)
rc = smb311_decode_neg_context(rsp, server,
rsp_iov.iov_len);
@@ -1292,14 +1357,13 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
cifs_tcon_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
- pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS);
+ pneg_inbuf = kmalloc_obj(*pneg_inbuf, GFP_NOFS);
if (!pneg_inbuf)
return -ENOMEM;
pneg_inbuf->Capabilities =
cpu_to_le32(server->vals->req_capabilities);
- if (tcon->ses->chan_max > 1)
- pneg_inbuf->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
+ pneg_inbuf->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
memcpy(pneg_inbuf->Guid, server->client_guid,
SMB2_CLIENT_GUID_SIZE);
@@ -1357,32 +1421,47 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
} else if (rc != 0) {
cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n",
rc);
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_neg_info_fail, rc);
goto out_free_inbuf;
}
- rc = -EIO;
if (rsplen != sizeof(*pneg_rsp)) {
cifs_tcon_dbg(VFS, "Invalid protocol negotiate response size: %d\n",
rsplen);
/* relax check since Mac returns max bufsize allowed on ioctl */
- if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp))
+ if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp)) {
+ rc = smb_EIO1(smb_eio_trace_neg_bad_rsplen, rsplen);
goto out_free_rsp;
+ }
}
/* check validate negotiate info response matches what we got earlier */
- if (pneg_rsp->Dialect != cpu_to_le16(server->dialect))
+ u16 dialect = le16_to_cpu(pneg_rsp->Dialect);
+
+ if (dialect != server->dialect) {
+ rc = smb_EIO2(smb_eio_trace_neg_info_dialect,
+ dialect, server->dialect);
goto vneg_out;
+ }
- if (pneg_rsp->SecurityMode != cpu_to_le16(server->sec_mode))
+ u16 sec_mode = le16_to_cpu(pneg_rsp->SecurityMode);
+
+ if (sec_mode != server->sec_mode) {
+ rc = smb_EIO2(smb_eio_trace_neg_info_sec_mode,
+ sec_mode, server->sec_mode);
goto vneg_out;
+ }
/* do not validate server guid because not saved at negprot time yet */
+ u32 caps = le32_to_cpu(pneg_rsp->Capabilities);
- if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND |
- SMB2_LARGE_FILES) != server->capabilities)
+ if ((caps | SMB2_NT_FIND |
+ SMB2_LARGE_FILES) != server->capabilities) {
+ rc = smb_EIO2(smb_eio_trace_neg_info_caps,
+ caps, server->capabilities);
goto vneg_out;
+ }
/* validate negotiate successful */
rc = 0;
@@ -1614,8 +1693,6 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
spnego_key = cifs_get_spnego_key(ses, server);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
- if (rc == -ENOKEY)
- cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n");
spnego_key = NULL;
goto out;
}
@@ -1636,19 +1713,17 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
- /* keep session key if binding */
- if (!is_binding) {
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
- GFP_KERNEL);
- if (!ses->auth_key.response) {
- cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
- msg->sesskey_len);
- rc = -ENOMEM;
- goto out_put_spnego_key;
- }
- ses->auth_key.len = msg->sesskey_len;
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = kmemdup(msg->data,
+ msg->sesskey_len,
+ GFP_KERNEL);
+ if (!ses->auth_key.response) {
+ cifs_dbg(VFS, "%s: can't allocate (%u bytes) memory\n",
+ __func__, msg->sesskey_len);
+ rc = -ENOMEM;
+ goto out_put_spnego_key;
}
+ ses->auth_key.len = msg->sesskey_len;
sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
sess_data->iov[1].iov_len = msg->secblob_len;
@@ -1707,7 +1782,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
* If memory allocation is successful, caller of this function
* frees it.
*/
- ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
+ ses->ntlmssp = kmalloc_obj(struct ntlmssp_auth);
if (!ses->ntlmssp) {
rc = -ENOMEM;
goto out_err;
@@ -1744,11 +1819,11 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
if (rc)
goto out;
- if (offsetof(struct smb2_sess_setup_rsp, Buffer) !=
- le16_to_cpu(rsp->SecurityBufferOffset)) {
- cifs_dbg(VFS, "Invalid security buffer offset %d\n",
- le16_to_cpu(rsp->SecurityBufferOffset));
- rc = -EIO;
+ u16 boff = le16_to_cpu(rsp->SecurityBufferOffset);
+
+ if (offsetof(struct smb2_sess_setup_rsp, Buffer) != boff) {
+ cifs_dbg(VFS, "Invalid security buffer offset %d\n", boff);
+ rc = smb_EIO1(smb_eio_trace_sess_buf_off, boff);
goto out;
}
rc = decode_ntlmssp_challenge(rsp->Buffer,
@@ -1902,10 +1977,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
if (!server) {
WARN(1, "%s: server is NULL!\n", __func__);
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
}
- sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL);
+ sess_data = kzalloc_obj(struct SMB2_sess_data);
if (!sess_data)
return -ENOMEM;
@@ -1952,10 +2027,9 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
cifs_dbg(FYI, "disconnect session %p\n", ses);
- if (ses && (ses->server))
- server = ses->server;
- else
- return -EIO;
+ if (!ses || !ses->server)
+ return smb_EIO(smb_eio_trace_null_pointers);
+ server = ses->server;
/* no need to send SMB logoff if uid already closed due to reconnect */
spin_lock(&ses->chan_lock);
@@ -2034,7 +2108,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
cifs_dbg(FYI, "TCON\n");
if (!server || !tree)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
if (unc_path == NULL)
@@ -2172,7 +2246,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
cifs_dbg(FYI, "Tree Disconnect\n");
if (!ses || !(ses->server))
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
trace_smb3_tdis_enter(xid, tcon->tid, ses->Suid, tcon->tree_name);
spin_lock(&ses->chan_lock);
@@ -2183,7 +2257,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
}
spin_unlock(&ses->chan_lock);
- invalidate_all_cached_dirs(tcon);
+ invalidate_all_cached_dirs(tcon, true);
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
(void **) &req,
@@ -2215,21 +2289,20 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
return rc;
}
-
-static struct create_durable *
+static create_durable_req_t *
create_durable_buf(void)
{
- struct create_durable *buf;
+ create_durable_req_t *buf;
- buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+ buf = kzalloc_obj(create_durable_req_t);
if (!buf)
return NULL;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
- (struct create_durable, Data));
+ (create_durable_req_t, Data));
buf->ccontext.DataLength = cpu_to_le32(16);
buf->ccontext.NameOffset = cpu_to_le16(offsetof
- (struct create_durable, Name));
+ (create_durable_req_t, Name));
buf->ccontext.NameLength = cpu_to_le16(4);
/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */
buf->Name[0] = 'D';
@@ -2239,20 +2312,20 @@ create_durable_buf(void)
return buf;
}
-static struct create_durable *
+static create_durable_req_t *
create_reconnect_durable_buf(struct cifs_fid *fid)
{
- struct create_durable *buf;
+ create_durable_req_t *buf;
- buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+ buf = kzalloc_obj(create_durable_req_t);
if (!buf)
return NULL;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
- (struct create_durable, Data));
+ (create_durable_req_t, Data));
buf->ccontext.DataLength = cpu_to_le32(16);
buf->ccontext.NameOffset = cpu_to_le16(offsetof
- (struct create_durable, Name));
+ (create_durable_req_t, Name));
buf->ccontext.NameLength = cpu_to_le16(4);
buf->Data.Fid.PersistentFileId = fid->persistent_fid;
buf->Data.Fid.VolatileFileId = fid->volatile_fid;
@@ -2392,11 +2465,16 @@ static int
add_lease_context(struct TCP_Server_Info *server,
struct smb2_create_req *req,
struct kvec *iov,
- unsigned int *num_iovec, u8 *lease_key, __u8 *oplock)
+ unsigned int *num_iovec,
+ u8 *lease_key,
+ __u8 *oplock,
+ u8 *parent_lease_key,
+ __le32 flags)
{
unsigned int num = *num_iovec;
- iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock);
+ iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock,
+ parent_lease_key, flags);
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = server->vals->create_lease_size;
@@ -2405,21 +2483,21 @@ add_lease_context(struct TCP_Server_Info *server,
return 0;
}
-static struct create_durable_v2 *
+static struct create_durable_req_v2 *
create_durable_v2_buf(struct cifs_open_parms *oparms)
{
struct cifs_fid *pfid = oparms->fid;
- struct create_durable_v2 *buf;
+ struct create_durable_req_v2 *buf;
- buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
+ buf = kzalloc_obj(struct create_durable_req_v2);
if (!buf)
return NULL;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
- (struct create_durable_v2, dcontext));
- buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
+ (struct create_durable_req_v2, dcontext));
+ buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2_req));
buf->ccontext.NameOffset = cpu_to_le16(offsetof
- (struct create_durable_v2, Name));
+ (struct create_durable_req_v2, Name));
buf->ccontext.NameLength = cpu_to_le16(4);
/*
@@ -2452,8 +2530,7 @@ create_reconnect_durable_v2_buf(struct cifs_fid *fid)
{
struct create_durable_handle_reconnect_v2 *buf;
- buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
- GFP_KERNEL);
+ buf = kzalloc_obj(struct create_durable_handle_reconnect_v2);
if (!buf)
return NULL;
@@ -2489,7 +2566,7 @@ add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
iov[num].iov_base = create_durable_v2_buf(oparms);
if (iov[num].iov_base == NULL)
return -ENOMEM;
- iov[num].iov_len = sizeof(struct create_durable_v2);
+ iov[num].iov_len = sizeof(struct create_durable_req_v2);
*num_iovec = num + 1;
return 0;
}
@@ -2533,7 +2610,7 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
iov[num].iov_base = create_durable_buf();
if (iov[num].iov_base == NULL)
return -ENOMEM;
- iov[num].iov_len = sizeof(struct create_durable);
+ iov[num].iov_len = sizeof(create_durable_req_t);
*num_iovec = num + 1;
return 0;
}
@@ -2544,7 +2621,7 @@ create_twarp_buf(__u64 timewarp)
{
struct crt_twarp_ctxt *buf;
- buf = kzalloc(sizeof(struct crt_twarp_ctxt), GFP_KERNEL);
+ buf = kzalloc_obj(struct crt_twarp_ctxt);
if (!buf)
return NULL;
@@ -2711,7 +2788,7 @@ create_query_id_buf(void)
{
struct crt_query_id_ctxt *buf;
- buf = kzalloc(sizeof(struct crt_query_id_ctxt), GFP_KERNEL);
+ buf = kzalloc_obj(struct crt_query_id_ctxt);
if (!buf)
return NULL;
@@ -2822,10 +2899,11 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
unsigned int total_len;
__le16 *utf16_path = NULL;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
+ pc_buf = NULL;
flags = 0;
n_iov = 2;
server = cifs_pick_channel(ses);
@@ -2838,7 +2916,7 @@ replay_again:
return -ENOMEM;
if (!ses || !server) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_null_pointers);
goto err_free_path;
}
@@ -2921,6 +2999,7 @@ replay_again:
req->CreateContextsOffset = cpu_to_le32(
sizeof(struct smb2_create_req) +
iov[1].iov_len);
+ le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len);
pc_buf = iov[n_iov-1].iov_base;
}
@@ -2933,8 +3012,12 @@ replay_again:
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
/* resource #4: response buffer */
rc = cifs_send_recv(xid, ses, server,
@@ -2954,20 +3037,21 @@ replay_again:
*/
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
if (rsp == NULL) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_mkdir_no_rsp);
kfree(pc_buf);
goto err_free_req;
}
trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
- CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES);
+ CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES,
+ rsp->OplockLevel);
SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId);
/* Eventually save off posix specific response info and timestamps */
err_free_rsp_buf:
- free_rsp_buf(resp_buftype, rsp);
+ free_rsp_buf(resp_buftype, rsp_iov.iov_base);
kfree(pc_buf);
err_free_req:
cifs_small_buf_release(req);
@@ -3068,7 +3152,9 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
req->RequestedOplockLevel = *oplock; /* no srv lease support */
else {
rc = add_lease_context(server, req, iov, &n_iov,
- oparms->fid->lease_key, oplock);
+ oparms->fid->lease_key, oplock,
+ oparms->fid->parent_lease_key,
+ oparms->lease_flags);
if (rc)
return rc;
}
@@ -3094,22 +3180,19 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
}
if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) {
+ unsigned int sbflags = cifs_sb_flags(oparms->cifs_sb);
bool set_mode;
bool set_owner;
- if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
- (oparms->mode != ACL_NO_MODE))
+ if ((sbflags & CIFS_MOUNT_MODE_FROM_SID) &&
+ oparms->mode != ACL_NO_MODE) {
set_mode = true;
- else {
+ } else {
set_mode = false;
oparms->mode = ACL_NO_MODE;
}
- if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
- set_owner = true;
- else
- set_owner = false;
-
+ set_owner = sbflags & CIFS_MOUNT_UID_FROM_ACL;
if (set_owner | set_mode) {
cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner);
@@ -3180,7 +3263,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3190,7 +3273,7 @@ replay_again:
cifs_dbg(FYI, "create/open\n");
if (!ses || !server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -3208,8 +3291,12 @@ replay_again:
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
oparms->create_options, oparms->desired_access);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -3234,9 +3321,6 @@ replay_again:
goto creat_exit;
} else if (rsp == NULL) /* unlikely to happen, but safer to check */
goto creat_exit;
- else
- trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
- oparms->create_options, oparms->desired_access);
atomic_inc(&tcon->num_remote_opens);
oparms->fid->persistent_fid = rsp->PersistentFileId;
@@ -3255,12 +3339,16 @@ replay_again:
buf->EndOfFile = rsp->EndofFile;
buf->Attributes = rsp->FileAttributes;
buf->NumberOfLinks = cpu_to_le32(1);
- buf->DeletePending = 0;
+ buf->DeletePending = 0; /* successful open = not delete pending */
}
rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch,
oparms->fid->lease_key, oplock, buf, posix);
+
+ trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
+ oparms->create_options, oparms->desired_access,
+ *oplock);
creat_exit:
SMB2_open_free(&rqst);
free_rsp_buf(resp_buftype, rsp);
@@ -3393,14 +3481,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
if (!tcon)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
ses = tcon->ses;
if (!ses)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
replay_again:
/* reinitialize for possible replay */
@@ -3408,7 +3496,7 @@ replay_again:
server = cifs_pick_channel(ses);
if (!server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
cifs_dbg(FYI, "SMB2 IOCTL\n");
@@ -3433,8 +3521,12 @@ replay_again:
if (rc)
goto ioctl_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -3471,7 +3563,7 @@ replay_again:
* warning)
*/
if (rsp == NULL) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_ioctl_no_rsp);
goto ioctl_exit;
}
@@ -3482,16 +3574,18 @@ replay_again:
goto ioctl_exit; /* server returned no data */
else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
cifs_tcon_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
+ rc = smb_EIO2(smb_eio_trace_ioctl_data_len, *plen, rsp_iov.iov_len);
*plen = 0;
- rc = -EIO;
goto ioctl_exit;
}
- if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
- cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
- le32_to_cpu(rsp->OutputOffset));
+ u32 outoff = le32_to_cpu(rsp->OutputOffset);
+
+ if (rsp_iov.iov_len - *plen < outoff) {
+ cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n",
+ *plen, outoff);
+ rc = smb_EIO2(smb_eio_trace_ioctl_out_off, rsp_iov.iov_len - *plen, outoff);
*plen = 0;
- rc = -EIO;
goto ioctl_exit;
}
@@ -3588,7 +3682,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int flags = 0;
bool query_attrs = false;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3599,7 +3693,7 @@ replay_again:
cifs_dbg(FYI, "Close\n");
if (!ses || !server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -3620,8 +3714,12 @@ replay_again:
if (rc)
goto close_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -3791,12 +3889,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
int flags = 0;
bool allocated = false;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
cifs_dbg(FYI, "Query Info\n");
if (!ses)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
replay_again:
/* reinitialize for possible replay */
@@ -3805,7 +3903,7 @@ replay_again:
server = cifs_pick_channel(ses);
if (!server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -3825,8 +3923,12 @@ replay_again:
trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
ses->Suid, info_class, (__u32)info_type);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -3888,23 +3990,6 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
NULL);
}
-#if 0
-/* currently unused, as now we are doing compounding instead (see smb311_posix_query_path_info) */
-int
-SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen)
-{
- size_t output_len = sizeof(struct smb311_posix_qinfo *) +
- (sizeof(struct smb_sid) * 2) + (PATH_MAX * 2);
- *plen = 0;
-
- return query_info(xid, tcon, persistent_fid, volatile_fid,
- SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0,
- output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen);
- /* Note caller must free "data" (passed in above). It may be allocated in query_info call */
-}
-#endif
-
int
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
@@ -3981,7 +4066,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3990,7 +4075,7 @@ replay_again:
cifs_dbg(FYI, "change notify\n");
if (!ses || !server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -4012,8 +4097,12 @@ replay_again:
trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -4032,9 +4121,12 @@ replay_again:
smb_rsp = (struct smb2_change_notify_rsp *)rsp_iov.iov_base;
- smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset),
- le32_to_cpu(smb_rsp->OutputBufferLength), &rsp_iov,
+ rc = smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset),
+ le32_to_cpu(smb_rsp->OutputBufferLength),
+ &rsp_iov,
sizeof(struct file_notify_information));
+ if (rc)
+ goto cnotify_exit;
*out_data = kmemdup((char *)smb_rsp + le16_to_cpu(smb_rsp->OutputBufferOffset),
le32_to_cpu(smb_rsp->OutputBufferLength), GFP_KERNEL);
@@ -4067,9 +4159,8 @@ replay_again:
* FIXME: maybe we should consider checking that the reply matches request?
*/
static void
-smb2_echo_callback(struct mid_q_entry *mid)
+smb2_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- struct TCP_Server_Info *server = mid->callback_data;
struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
struct cifs_credits credits = { .value = 0, .instance = 0 };
@@ -4079,7 +4170,7 @@ smb2_echo_callback(struct mid_q_entry *mid)
credits.instance = server->reconnect_instance;
}
- release_mid(mid);
+ release_mid(server, mid);
add_credits(server, &credits, CIFS_ECHO_OP);
}
@@ -4092,12 +4183,8 @@ static void cifs_renegotiate_iosize(struct TCP_Server_Info *server,
return;
spin_lock(&tcon->sb_list_lock);
- list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link) {
- cifs_sb->ctx->rsize =
- server->ops->negotiate_rsize(tcon, cifs_sb->ctx);
- cifs_sb->ctx->wsize =
- server->ops->negotiate_wsize(tcon, cifs_sb->ctx);
- }
+ list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link)
+ cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
spin_unlock(&tcon->sb_list_lock);
}
@@ -4153,7 +4240,9 @@ void smb2_reconnect_server(struct work_struct *work)
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect || tcon->need_reopen_files) {
+ spin_lock(&tcon->tc_lock);
tcon->tc_count++;
+ spin_unlock(&tcon->tc_lock);
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_reconnect_server);
list_add_tail(&tcon->rlist, &tmp_list);
@@ -4211,10 +4300,8 @@ void smb2_reconnect_server(struct work_struct *work)
}
goto done;
}
-
tcon->status = TID_GOOD;
- tcon->retry = false;
- tcon->need_reconnect = false;
+ tcon->dummy = true;
/* now reconnect sessions for necessary channels */
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
@@ -4230,7 +4317,7 @@ void smb2_reconnect_server(struct work_struct *work)
done:
cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
if (resched)
- queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
+ cifs_requeue_server_reconn(server);
mutex_unlock(&pserver->reconnect_mutex);
/* now we can safely release srv struct */
@@ -4254,7 +4341,7 @@ SMB2_echo(struct TCP_Server_Info *server)
server->ops->need_neg(server)) {
spin_unlock(&server->srv_lock);
/* No need to send echo on newly established connections */
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ cifs_queue_server_reconn(server);
return rc;
}
spin_unlock(&server->srv_lock);
@@ -4321,7 +4408,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -4330,7 +4417,7 @@ replay_again:
cifs_dbg(FYI, "flush\n");
if (!ses || !(ses->server))
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -4347,8 +4434,12 @@ replay_again:
trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -4395,7 +4486,7 @@ static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms)
return false;
/* offload also has its overhead, so only do it if desired */
- if (io_parms->length < server->smbd_conn->rdma_readwrite_threshold)
+ if (io_parms->length < server->rdma_readwrite_threshold)
return false;
return true;
@@ -4445,10 +4536,10 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
#ifdef CONFIG_CIFS_SMB_DIRECT
/*
* If we want to do a RDMA write, fill in and append
- * smbd_buffer_descriptor_v1 to the end of read request
+ * smbdirect_buffer_descriptor_v1 to the end of read request
*/
if (rdata && smb3_use_rdma_offload(io_parms)) {
- struct smbd_buffer_descriptor_v1 *v1;
+ struct smbdirect_buffer_descriptor_v1 *v1;
bool need_invalidate = server->dialect == SMB30_PROT_ID;
rdata->mr = smbd_register_mr(server->smbd_conn, &rdata->subreq.io_iter,
@@ -4462,11 +4553,9 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
req->ReadChannelInfoOffset =
cpu_to_le16(offsetof(struct smb2_read_req, Buffer));
req->ReadChannelInfoLength =
- cpu_to_le16(sizeof(struct smbd_buffer_descriptor_v1));
- v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0];
- v1->offset = cpu_to_le64(rdata->mr->mr->iova);
- v1->token = cpu_to_le32(rdata->mr->mr->rkey);
- v1->length = cpu_to_le32(rdata->mr->mr->length);
+ cpu_to_le16(sizeof(struct smbdirect_buffer_descriptor_v1));
+ v1 = (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0];
+ smbd_mr_fill_buffer_descriptor(rdata->mr, v1);
*total_len += sizeof(*v1) - 1;
}
@@ -4500,21 +4589,19 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
}
static void
-smb2_readv_callback(struct mid_q_entry *mid)
+smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
struct cifs_io_subrequest *rdata = mid->callback_data;
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
- struct TCP_Server_Info *server = rdata->server;
- struct smb2_hdr *shdr =
- (struct smb2_hdr *)rdata->iov[0].iov_base;
+ struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base;
struct cifs_credits credits = {
.value = 0,
.instance = 0,
.rreq_debug_id = rdata->rreq->debug_id,
.rreq_debug_index = rdata->subreq.debug_index,
};
- struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], .rq_nvec = 1 };
+ struct smb_rqst rqst = { .rq_iov = &rdata->iov[0], .rq_nvec = 1 };
unsigned int rreq_debug_id = rdata->rreq->debug_id;
unsigned int subreq_debug_index = rdata->subreq.debug_index;
@@ -4522,9 +4609,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
rqst.rq_iter = rdata->subreq.io_iter;
}
- WARN_ONCE(rdata->server != mid->server,
+ WARN_ONCE(rdata->server != server,
"rdata server %p != mid server %p",
- rdata->server, mid->server);
+ rdata->server, server);
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu/%zu\n",
__func__, mid->mid, mid->mid_state, rdata->result,
@@ -4540,16 +4627,30 @@ smb2_readv_callback(struct mid_q_entry *mid)
iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
rc = smb2_verify_signature(&rqst, server);
- if (rc)
+ if (rc) {
cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n",
- rc);
+ rc);
+ rdata->subreq.error = rc;
+ rdata->result = rc;
+
+ if (is_replayable_error(rc)) {
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
+ } else
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_bad);
+ } else
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
}
/* FIXME: should this be counted toward the initiating task? */
task_io_account_read(rdata->got_bytes);
cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
case MID_REQUEST_SUBMITTED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted);
+ goto do_retry;
case MID_RETRY_NEEDED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
+do_retry:
__set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
rdata->result = -EAGAIN;
if (server->sign && rdata->got_bytes)
@@ -4560,11 +4661,16 @@ smb2_readv_callback(struct mid_q_entry *mid)
cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
case MID_RESPONSE_MALFORMED:
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed);
credits.value = le16_to_cpu(shdr->CreditRequest);
credits.instance = server->reconnect_instance;
- fallthrough;
+ rdata->result = smb_EIO(smb_eio_trace_read_rsp_malformed);
+ break;
default:
- rdata->result = -EIO;
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown);
+ rdata->result = smb_EIO1(smb_eio_trace_read_mid_state_unknown,
+ mid->mid_state);
+ break;
}
#ifdef CONFIG_CIFS_SMB_DIRECT
/*
@@ -4602,13 +4708,21 @@ smb2_readv_callback(struct mid_q_entry *mid)
} else {
size_t trans = rdata->subreq.transferred + rdata->got_bytes;
if (trans < rdata->subreq.len &&
- rdata->subreq.start + trans == ictx->remote_i_size) {
+ rdata->subreq.start + trans >= ictx->remote_i_size) {
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
rdata->result = 0;
}
if (rdata->got_bytes)
__set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags);
}
+
+ /* see if we need to retry */
+ if (is_replayable_error(rdata->result) &&
+ smb2_should_replay(tcon,
+ &rdata->retries,
+ &rdata->cur_sleep))
+ rdata->replay = true;
+
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
server->credits, server->in_flight,
0, cifs_trace_rw_credits_read_response_clear);
@@ -4617,7 +4731,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
rdata->subreq.transferred += rdata->got_bytes;
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
netfs_read_subreq_terminated(&rdata->subreq);
- release_mid(mid);
+ release_mid(server, mid);
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
server->credits, server->in_flight,
credits.value, cifs_trace_rw_credits_read_response_add);
@@ -4657,7 +4771,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
rc = smb2_new_read_req(
(void **) &buf, &total_len, &io_parms, rdata, 0, 0);
if (rc)
- return rc;
+ goto out;
if (smb3_encryption_required(io_parms.tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -4669,6 +4783,13 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
shdr = (struct smb2_hdr *)buf;
+ if (rdata->replay) {
+ /* Back-off before retry */
+ if (rdata->cur_sleep)
+ msleep(rdata->cur_sleep);
+ smb2_set_replay(server, &rqst);
+ }
+
if (rdata->credits.value > 0) {
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(io_parms.length,
SMB2_MAX_BUFFER_SIZE));
@@ -4704,6 +4825,17 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
async_readv_out:
cifs_small_buf_release(buf);
+
+out:
+ /* if the send error is retryable, let netfs know about it */
+ if (is_replayable_error(rc) &&
+ smb2_should_replay(tcon,
+ &rdata->retries,
+ &rdata->cur_sleep)) {
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
+ }
+
return rc;
}
@@ -4772,7 +4904,8 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
(*nbytes > io_parms->length)) {
cifs_dbg(FYI, "bad length %d for count %d\n",
*nbytes, io_parms->length);
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_read_overlarge,
+ *nbytes, io_parms->length);
*nbytes = 0;
}
@@ -4794,11 +4927,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
* workqueue completion task.
*/
static void
-smb2_writev_callback(struct mid_q_entry *mid)
+smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
struct cifs_io_subrequest *wdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
- struct TCP_Server_Info *server = wdata->server;
struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
struct cifs_credits credits = {
.value = 0,
@@ -4811,17 +4943,26 @@ smb2_writev_callback(struct mid_q_entry *mid)
ssize_t result = 0;
size_t written;
- WARN_ONCE(wdata->server != mid->server,
+ WARN_ONCE(wdata->server != server,
"wdata server %p != mid server %p",
- wdata->server, mid->server);
+ wdata->server, server);
switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
credits.instance = server->reconnect_instance;
result = smb2_check_receive(mid, server, 0);
- if (result != 0)
+ if (result != 0) {
+ if (is_replayable_error(result)) {
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ } else {
+ wdata->subreq.error = result;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
+ }
break;
+ }
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
written = le32_to_cpu(rsp->DataLength);
/*
@@ -4836,22 +4977,32 @@ smb2_writev_callback(struct mid_q_entry *mid)
cifs_stats_bytes_written(tcon, written);
if (written < wdata->subreq.len) {
- wdata->result = -ENOSPC;
+ result = -ENOSPC;
} else if (written > 0) {
wdata->subreq.len = written;
__set_bit(NETFS_SREQ_MADE_PROGRESS, &wdata->subreq.flags);
}
break;
case MID_REQUEST_SUBMITTED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_req_submitted);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ result = -EAGAIN;
+ break;
case MID_RETRY_NEEDED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
result = -EAGAIN;
break;
case MID_RESPONSE_MALFORMED:
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_malformed);
credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
credits.instance = server->reconnect_instance;
- fallthrough;
+ result = smb_EIO(smb_eio_trace_write_rsp_malformed);
+ break;
default:
- result = -EIO;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown);
+ result = smb_EIO1(smb_eio_trace_write_mid_state_unknown,
+ mid->mid_state);
break;
}
#ifdef CONFIG_CIFS_SMB_DIRECT
@@ -4868,6 +5019,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
}
#endif
if (result) {
+ wdata->result = result;
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
trace_smb3_write_err(wdata->rreq->debug_id,
wdata->subreq.debug_index,
@@ -4890,9 +5042,16 @@ smb2_writev_callback(struct mid_q_entry *mid)
server->credits, server->in_flight,
0, cifs_trace_rw_credits_write_response_clear);
wdata->credits.value = 0;
- trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
- cifs_write_subrequest_terminated(wdata, result ?: written, true);
- release_mid(mid);
+
+ /* see if we need to retry */
+ if (is_replayable_error(wdata->result) &&
+ smb2_should_replay(tcon,
+ &wdata->retries,
+ &wdata->cur_sleep))
+ wdata->replay = true;
+
+ cifs_write_subrequest_terminated(wdata, result ?: written);
+ release_mid(server, mid);
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
server->credits, server->in_flight,
credits.value, cifs_trace_rw_credits_write_response_add);
@@ -4971,10 +5130,10 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
#ifdef CONFIG_CIFS_SMB_DIRECT
/*
* If we want to do a server RDMA read, fill in and append
- * smbd_buffer_descriptor_v1 to the end of write request
+ * smbdirect_buffer_descriptor_v1 to the end of write request
*/
if (smb3_use_rdma_offload(io_parms)) {
- struct smbd_buffer_descriptor_v1 *v1;
+ struct smbdirect_buffer_descriptor_v1 *v1;
bool need_invalidate = server->dialect == SMB30_PROT_ID;
wdata->mr = smbd_register_mr(server->smbd_conn, &wdata->subreq.io_iter,
@@ -4993,11 +5152,9 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
req->WriteChannelInfoOffset =
cpu_to_le16(offsetof(struct smb2_write_req, Buffer));
req->WriteChannelInfoLength =
- cpu_to_le16(sizeof(struct smbd_buffer_descriptor_v1));
- v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0];
- v1->offset = cpu_to_le64(wdata->mr->mr->iova);
- v1->token = cpu_to_le32(wdata->mr->mr->rkey);
- v1->length = cpu_to_le32(wdata->mr->mr->length);
+ cpu_to_le16(sizeof(struct smbdirect_buffer_descriptor_v1));
+ v1 = (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0];
+ smbd_mr_fill_buffer_descriptor(wdata->mr, v1);
rqst.rq_iov[0].iov_len += sizeof(*v1);
@@ -5009,8 +5166,12 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
}
#endif
- if (wdata->subreq.retry_count > 0)
+ if (wdata->replay) {
+ /* Back-off before retry */
+ if (wdata->cur_sleep)
+ msleep(wdata->cur_sleep);
smb2_set_replay(server, &rqst);
+ }
cifs_dbg(FYI, "async write at %llu %u bytes iter=%zx\n",
io_parms->offset, io_parms->length, iov_iter_count(&wdata->subreq.io_iter));
@@ -5056,6 +5217,16 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
async_writev_out:
cifs_small_buf_release(req);
out:
+ /* if the send error is retryable, let netfs know about it */
+ if (is_replayable_error(rc) &&
+ smb2_should_replay(tcon,
+ &wdata->retries,
+ &wdata->cur_sleep)) {
+ wdata->replay = true;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ }
+
if (rc) {
trace_smb3_rw_credits(wdata->rreq->debug_id,
wdata->subreq.debug_index,
@@ -5064,7 +5235,7 @@ out:
-(int)wdata->credits.value,
cifs_trace_rw_credits_write_response_clear);
add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
- cifs_write_subrequest_terminated(wdata, rc, true);
+ cifs_write_subrequest_terminated(wdata, rc);
}
}
@@ -5087,7 +5258,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
int flags = 0;
unsigned int total_len;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5133,10 +5304,17 @@ replay_again:
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov;
- rqst.rq_nvec = n_vec + 1;
+ /* iov[0] is the SMB header; move payload to rq_iter for encryption safety */
+ rqst.rq_nvec = 1;
+ iov_iter_kvec(&rqst.rq_iter, ITER_SOURCE, &iov[1], n_vec,
+ io_parms->length);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
&rqst,
@@ -5416,7 +5594,7 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
info_buf_size = sizeof(FILE_DIRECTORY_INFO);
break;
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
- info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO);
+ info_buf_size = sizeof(FILE_ID_FULL_DIR_INFO);
break;
case SMB_FIND_FILE_POSIX_INFO:
/* note that posix payload are variable size */
@@ -5487,7 +5665,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5495,7 +5673,7 @@ replay_again:
server = cifs_pick_channel(ses);
if (!ses || !(ses->server))
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -5512,8 +5690,12 @@ replay_again:
if (rc)
goto qdir_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -5622,7 +5804,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5630,7 +5812,7 @@ replay_again:
server = cifs_pick_channel(ses);
if (!ses || !server)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
if (!num)
return -EINVAL;
@@ -5638,7 +5820,7 @@ replay_again:
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
- iov = kmalloc_array(num, sizeof(struct kvec), GFP_KERNEL);
+ iov = kmalloc_objs(struct kvec, num);
if (!iov)
return -ENOMEM;
@@ -5655,8 +5837,12 @@ replay_again:
return rc;
}
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -5735,7 +5921,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
struct kvec iov[1];
struct kvec rsp_iov;
int resp_buf_type;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5765,8 +5951,12 @@ replay_again:
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buf_type, flags, &rsp_iov);
@@ -5827,7 +6017,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
cifs_dbg(FYI, "Query FSInfo level %d\n", level);
if ((tcon->ses == NULL) || server == NULL)
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
(void **) &req, &total_len);
@@ -5868,7 +6058,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
FILE_SYSTEM_POSIX_INFO *info = NULL;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5889,8 +6079,12 @@ replay_again:
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -5920,71 +6114,6 @@ posix_qfsinf_exit:
}
int
-SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
-{
- struct smb_rqst rqst;
- struct smb2_query_info_rsp *rsp = NULL;
- struct kvec iov;
- struct kvec rsp_iov;
- int rc = 0;
- int resp_buftype;
- struct cifs_ses *ses = tcon->ses;
- struct TCP_Server_Info *server;
- struct smb2_fs_full_size_info *info = NULL;
- int flags = 0;
- int retries = 0, cur_sleep = 1;
-
-replay_again:
- /* reinitialize for possible replay */
- flags = 0;
- server = cifs_pick_channel(ses);
-
- rc = build_qfs_info_req(&iov, tcon, server,
- FS_FULL_SIZE_INFORMATION,
- sizeof(struct smb2_fs_full_size_info),
- persistent_fid, volatile_fid);
- if (rc)
- return rc;
-
- if (smb3_encryption_required(tcon))
- flags |= CIFS_TRANSFORM_REQ;
-
- memset(&rqst, 0, sizeof(struct smb_rqst));
- rqst.rq_iov = &iov;
- rqst.rq_nvec = 1;
-
- if (retries)
- smb2_set_replay(server, &rqst);
-
- rc = cifs_send_recv(xid, ses, server,
- &rqst, &resp_buftype, flags, &rsp_iov);
- free_qfs_info_req(&iov);
- if (rc) {
- cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
- goto qfsinf_exit;
- }
- rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
-
- info = (struct smb2_fs_full_size_info *)(
- le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
- rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
- le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
- sizeof(struct smb2_fs_full_size_info));
- if (!rc)
- smb2_copy_fs_info_to_kstatfs(info, fsdata);
-
-qfsinf_exit:
- free_rsp_buf(resp_buftype, rsp_iov.iov_base);
-
- if (is_replayable_error(rc) &&
- smb2_should_replay(tcon, &retries, &cur_sleep))
- goto replay_again;
-
- return rc;
-}
-
-int
SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int level)
{
@@ -5998,7 +6127,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
unsigned int rsp_len, offset;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -6009,14 +6138,14 @@ replay_again:
max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
min_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
} else if (level == FS_ATTRIBUTE_INFORMATION) {
- max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO);
- min_len = MIN_FS_ATTR_INFO_SIZE;
+ max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + MAX_FS_NAME_LEN;
+ min_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO);
} else if (level == FS_SECTOR_SIZE_INFORMATION) {
max_len = sizeof(struct smb3_fs_ss_info);
min_len = sizeof(struct smb3_fs_ss_info);
} else if (level == FS_VOLUME_INFORMATION) {
- max_len = sizeof(struct smb3_fs_vol_info) + MAX_VOL_LABEL_LEN;
- min_len = sizeof(struct smb3_fs_vol_info);
+ max_len = sizeof(struct filesystem_vol_info) + MAX_VOL_LABEL_LEN;
+ min_len = sizeof(struct filesystem_vol_info);
} else {
cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level);
return -EINVAL;
@@ -6035,8 +6164,12 @@ replay_again:
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -6056,7 +6189,7 @@ replay_again:
if (level == FS_ATTRIBUTE_INFORMATION)
memcpy(&tcon->fsAttrInfo, offset
+ (char *)rsp, min_t(unsigned int,
- rsp_len, max_len));
+ rsp_len, min_len));
else if (level == FS_DEVICE_INFORMATION)
memcpy(&tcon->fsDevInfo, offset
+ (char *)rsp, sizeof(FILE_SYSTEM_DEVICE_INFO));
@@ -6067,9 +6200,9 @@ replay_again:
tcon->perf_sector_size =
le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
} else if (level == FS_VOLUME_INFORMATION) {
- struct smb3_fs_vol_info *vol_info = (struct smb3_fs_vol_info *)
+ struct filesystem_vol_info *vol_info = (struct filesystem_vol_info *)
(offset + (char *)rsp);
- tcon->vol_serial_number = vol_info->VolumeSerialNumber;
+ tcon->vol_serial_number = le32_to_cpu(vol_info->VolumeSerialNumber);
tcon->vol_create_time = vol_info->VolumeCreationTime;
}
@@ -6098,7 +6231,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
int flags = CIFS_NO_RSP_BUF;
unsigned int total_len;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -6134,8 +6267,17 @@ replay_again:
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
+
+ trace_smb3_lock_enter(xid, persist_fid, tcon->tid, tcon->ses->Suid,
+ le64_to_cpu(buf[0].Offset),
+ le64_to_cpu(buf[0].Length),
+ le32_to_cpu(buf[0].Flags), num_lock, 0);
rc = cifs_send_recv(xid, tcon->ses, server,
&rqst, &resp_buf_type, flags,
@@ -6145,7 +6287,15 @@ replay_again:
cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
trace_smb3_lock_err(xid, persist_fid, tcon->tid,
- tcon->ses->Suid, rc);
+ tcon->ses->Suid,
+ le64_to_cpu(buf[0].Offset),
+ le64_to_cpu(buf[0].Length),
+ le32_to_cpu(buf[0].Flags), num_lock, rc);
+ } else {
+ trace_smb3_lock_done(xid, persist_fid, tcon->tid, tcon->ses->Suid,
+ le64_to_cpu(buf[0].Offset),
+ le64_to_cpu(buf[0].Length),
+ le32_to_cpu(buf[0].Flags), num_lock, 0);
}
if (is_replayable_error(rc) &&
@@ -6222,11 +6372,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
please_key_high = (__u64 *)(lease_key+8);
if (rc) {
cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
- trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid,
+ trace_smb3_lease_ack_err(le32_to_cpu(lease_state), tcon->tid,
ses->Suid, *please_key_low, *please_key_high, rc);
cifs_dbg(FYI, "Send error in Lease Break = %d\n", rc);
} else
- trace_smb3_lease_done(le32_to_cpu(lease_state), tcon->tid,
+ trace_smb3_lease_ack_done(le32_to_cpu(lease_state), tcon->tid,
ses->Suid, *please_key_low, *please_key_high);
return rc;
diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h
index 3c09a58dfd07..30d70097fe2f 100644
--- a/fs/smb/client/smb2pdu.h
+++ b/fs/smb/client/smb2pdu.h
@@ -133,46 +133,6 @@ struct share_redirect_error_context_rsp {
#define SMB2_LEASE_HANDLE_CACHING_HE 0x02
#define SMB2_LEASE_WRITE_CACHING_HE 0x04
-
-/* See MS-SMB2 2.2.13.2.11 */
-/* Flags */
-#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
-struct durable_context_v2 {
- __le32 Timeout;
- __le32 Flags;
- __u64 Reserved;
- __u8 CreateGuid[16];
-} __packed;
-
-struct create_durable_v2 {
- struct create_context_hdr ccontext;
- __u8 Name[8];
- struct durable_context_v2 dcontext;
-} __packed;
-
-/* See MS-SMB2 2.2.13.2.12 */
-struct durable_reconnect_context_v2 {
- struct {
- __u64 PersistentFileId;
- __u64 VolatileFileId;
- } Fid;
- __u8 CreateGuid[16];
- __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
-} __packed;
-
-/* See MS-SMB2 2.2.14.2.12 */
-struct durable_reconnect_context_v2_rsp {
- __le32 Timeout;
- __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
-} __packed;
-
-struct create_durable_handle_reconnect_v2 {
- struct create_context_hdr ccontext;
- __u8 Name[8];
- struct durable_reconnect_context_v2 dcontext;
- __u8 Pad[4];
-} __packed;
-
/* See MS-SMB2 2.2.13.2.5 */
struct crt_twarp_ctxt {
struct create_context_hdr ccontext;
@@ -193,32 +153,6 @@ struct crt_sd_ctxt {
struct smb3_sd sd;
} __packed;
-
-#define COPY_CHUNK_RES_KEY_SIZE 24
-struct resume_key_req {
- char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
- __le32 ContextLength; /* MBZ */
- char Context[]; /* ignored, Windows sets to 4 bytes of zero */
-} __packed;
-
-/* this goes in the ioctl buffer when doing a copychunk request */
-struct copychunk_ioctl {
- char SourceKey[COPY_CHUNK_RES_KEY_SIZE];
- __le32 ChunkCount; /* we are only sending 1 */
- __le32 Reserved;
- /* array will only be one chunk long for us */
- __le64 SourceOffset;
- __le64 TargetOffset;
- __le32 Length; /* how many bytes to copy */
- __u32 Reserved2;
-} __packed;
-
-struct copychunk_ioctl_rsp {
- __le32 ChunksWritten;
- __le32 ChunkBytesWritten;
- __le32 TotalBytesWritten;
-} __packed;
-
/* See MS-FSCC 2.3.29 and 2.3.30 */
struct get_retrieval_pointer_count_req {
__le64 StartingVcn; /* virtual cluster number (signed) */
@@ -259,35 +193,6 @@ struct network_resiliency_req {
} __packed;
/* There is no buffer for the response ie no struct network_resiliency_rsp */
-#define RSS_CAPABLE cpu_to_le32(0x00000001)
-#define RDMA_CAPABLE cpu_to_le32(0x00000002)
-
-#define INTERNETWORK cpu_to_le16(0x0002)
-#define INTERNETWORKV6 cpu_to_le16(0x0017)
-
-struct network_interface_info_ioctl_rsp {
- __le32 Next; /* next interface. zero if this is last one */
- __le32 IfIndex;
- __le32 Capability; /* RSS or RDMA Capable */
- __le32 Reserved;
- __le64 LinkSpeed;
- __le16 Family;
- __u8 Buffer[126];
-} __packed;
-
-struct iface_info_ipv4 {
- __be16 Port;
- __be32 IPv4Address;
- __be64 Reserved;
-} __packed;
-
-struct iface_info_ipv6 {
- __be16 Port;
- __be32 FlowInfo;
- __u8 IPv6Address[16];
- __be32 ScopeId;
-} __packed;
-
#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
struct compress_ioctl {
@@ -319,20 +224,7 @@ struct smb2_file_reparse_point_info {
__le32 Tag;
} __packed;
-struct smb2_file_network_open_info {
- struct_group_attr(network_open_info, __packed,
- __le64 CreationTime;
- __le64 LastAccessTime;
- __le64 LastWriteTime;
- __le64 ChangeTime;
- __le64 AllocationSize;
- __le64 EndOfFile;
- __le32 Attributes;
- );
- __le32 Reserved;
-} __packed; /* level 34 Query also similar returned in close rsp and open rsp */
-
-/* See MS-FSCC 2.4.21 */
+/* See MS-FSCC 2.4.26 */
struct smb2_file_id_information {
__le64 VolumeSerialNumber;
__u64 PersistentFileId; /* opaque endianness */
@@ -359,7 +251,10 @@ struct smb2_file_id_extd_directory_info {
extern char smb2_padding[7];
-/* equivalent of the contents of SMB3.1.1 POSIX open context response */
+/*
+ * See POSIX-SMB2 2.2.14.2.16
+ * Link: https://gitlab.com/samba-team/smb3-posix-spec/-/blob/master/smb3_posix_extensions.md
+ */
struct create_posix_rsp {
u32 nlink;
u32 reparse_tag;
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 4662c7e2d259..1ceb95b907e6 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -9,10 +9,11 @@
*/
#ifndef _SMB2PROTO_H
#define _SMB2PROTO_H
+
#include <linux/nls.h>
#include <linux/key-type.h>
+#include "cached_dir.h"
-struct statfs;
struct smb_rqst;
/*
@@ -20,308 +21,254 @@ struct smb_rqst;
* All Prototypes
*****************************************************************
*/
-extern int map_smb2_to_linux_error(char *buf, bool log_err);
-extern int smb2_check_message(char *buf, unsigned int length,
- struct TCP_Server_Info *server);
-extern unsigned int smb2_calc_size(void *buf);
-extern char *smb2_get_data_area_len(int *off, int *len,
- struct smb2_hdr *shdr);
-extern __le16 *cifs_convert_path_to_utf16(const char *from,
- struct cifs_sb_info *cifs_sb);
+int map_smb2_to_linux_error(char *buf, bool log_err);
+int smb2_init_maperror(void);
+#if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
+const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status);
+extern const struct status_to_posix_error *smb2_error_map_table_test;
+extern unsigned int smb2_error_map_num;
+#endif
-extern int smb2_verify_signature(struct smb_rqst *, struct TCP_Server_Info *);
-extern int smb2_check_receive(struct mid_q_entry *mid,
- struct TCP_Server_Info *server, bool log_error);
-extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
- struct TCP_Server_Info *,
- struct smb_rqst *rqst);
-extern struct mid_q_entry *smb2_setup_async_request(
- struct TCP_Server_Info *server, struct smb_rqst *rqst);
-extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
- __u64 ses_id, __u32 tid);
-extern int smb2_calc_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server,
- bool allocate_crypto);
-extern int smb3_calc_signature(struct smb_rqst *rqst,
- struct TCP_Server_Info *server,
- bool allocate_crypto);
-extern void smb2_echo_request(struct work_struct *work);
-extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
-extern bool smb2_is_valid_oplock_break(char *buffer,
- struct TCP_Server_Info *srv);
-extern int smb3_handle_read_data(struct TCP_Server_Info *server,
- struct mid_q_entry *mid);
-extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *path,
- __u32 *reparse_tag);
-struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
- struct super_block *sb,
- const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *full_path,
- bool directory,
- struct kvec *reparse_iov,
- struct kvec *xattr_iov);
-int smb2_query_reparse_point(const unsigned int xid,
- struct cifs_tcon *tcon,
+int smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
+ struct TCP_Server_Info *server);
+unsigned int smb2_calc_size(void *buf);
+char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr);
+__le16 *cifs_convert_path_to_utf16(const char *from,
+ struct cifs_sb_info *cifs_sb);
+
+int smb2_verify_signature(struct smb_rqst *rqst,
+ struct TCP_Server_Info *server);
+int smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+ bool log_error);
+struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ struct smb_rqst *rqst);
+struct mid_q_entry *smb2_setup_async_request(struct TCP_Server_Info *server,
+ struct smb_rqst *rqst);
+struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
+ __u64 ses_id, __u32 tid);
+__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock);
+bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server);
+int smb3_handle_read_data(struct TCP_Server_Info *server,
+ struct mid_q_entry *mid);
+struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid,
+ struct cifs_tcon *tcon,
+ const char *full_path, bool directory,
+ struct kvec *reparse_iov,
+ struct kvec *xattr_iov);
+int smb2_query_reparse_point(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
- const char *full_path,
- u32 *tag, struct kvec *rsp,
+ const char *full_path, u32 *tag, struct kvec *rsp,
int *rsp_buftype);
-int smb2_query_path_info(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb,
- const char *full_path,
+int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb, const char *full_path,
struct cifs_open_info_data *data);
-extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
- const char *full_path, __u64 size,
- struct cifs_sb_info *cifs_sb, bool set_alloc,
- struct dentry *dentry);
-extern int smb2_set_file_info(struct inode *inode, const char *full_path,
- FILE_BASIC_INFO *buf, const unsigned int xid);
-extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
- umode_t mode, struct cifs_tcon *tcon,
- const char *full_path,
- struct cifs_sb_info *cifs_sb);
-extern int smb2_mkdir(const unsigned int xid, struct inode *inode,
- umode_t mode, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb);
-extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
- struct cifs_sb_info *cifs_sb,
- struct cifs_tcon *tcon, const unsigned int xid);
-extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb);
-extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb,
- struct dentry *dentry);
-int smb2_rename_path(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct dentry *source_dentry,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb);
-int smb2_create_hardlink(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct dentry *source_dentry,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb);
-extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const unsigned char *path,
- char *pbuf, unsigned int *pbytes_written);
-extern int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *full_path, __u64 size,
+ struct cifs_sb_info *cifs_sb, bool set_alloc,
+ struct dentry *dentry);
+int smb2_set_file_info(struct inode *inode, const char *full_path,
+ FILE_BASIC_INFO *buf, const unsigned int xid);
+int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
+ umode_t mode, struct cifs_tcon *tcon,
+ const char *full_path, struct cifs_sb_info *cifs_sb);
+int smb2_mkdir(const unsigned int xid, struct inode *parent_inode,
+ umode_t mode, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb);
+void smb2_mkdir_setinfo(struct inode *inode, const char *name,
+ struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ const unsigned int xid);
+int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
+int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb,
+ struct dentry *dentry);
+int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+ struct dentry *source_dentry, const char *from_name,
+ const char *to_name, struct cifs_sb_info *cifs_sb);
+int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+ struct dentry *source_dentry, const char *from_name,
+ const char *to_name, struct cifs_sb_info *cifs_sb);
+int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const unsigned char *path, char *pbuf,
+ unsigned int *pbytes_written);
+int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_read);
-int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb);
+int smb2_fix_symlink_target_type(char **target, bool directory,
+ struct cifs_sb_info *cifs_sb);
int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
- bool relative,
- const char *full_path,
+ bool relative, const char *full_path,
struct cifs_sb_info *cifs_sb);
int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb,
- const struct kvec *iov,
- const char *full_path,
+ const struct kvec *iov, const char *full_path,
char **path);
-int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
- void *buf);
-extern int smb2_unlock_range(struct cifsFileInfo *cfile,
- struct file_lock *flock, const unsigned int xid);
-extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
-extern void smb2_reconnect_server(struct work_struct *work);
-extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
-extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
- struct smb_rqst *rqst);
-extern void smb2_set_next_command(struct cifs_tcon *tcon,
- struct smb_rqst *rqst);
-extern void smb2_set_related(struct smb_rqst *rqst);
-extern void smb2_set_replay(struct TCP_Server_Info *server,
- struct smb_rqst *rqst);
-extern bool smb2_should_replay(struct cifs_tcon *tcon,
- int *pretries,
- int *pcur_sleep);
+int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
+ __u32 *oplock, void *buf);
+int smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
+ const unsigned int xid);
+int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
+void smb2_reconnect_server(struct work_struct *work);
+int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
+unsigned long smb_rqst_len(struct TCP_Server_Info *server,
+ struct smb_rqst *rqst);
+void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst);
+void smb2_set_related(struct smb_rqst *rqst);
+void smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst);
+bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries,
+ int *pcur_sleep);
/*
* SMB2 Worker functions - most of protocol specific implementation details
* are contained within these calls.
*/
-extern int SMB2_negotiate(const unsigned int xid,
- struct cifs_ses *ses,
- struct TCP_Server_Info *server);
-extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- const struct nls_table *nls_cp);
-extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses);
-extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
- const char *tree, struct cifs_tcon *tcon,
- const struct nls_table *);
-extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
-extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
- __le16 *path, __u8 *oplock,
- struct smb2_file_all_info *buf,
- struct create_posix_rsp *posix,
- struct kvec *err_iov, int *resp_buftype);
-extern int SMB2_open_init(struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- __u8 *oplock, struct cifs_open_parms *oparms,
- __le16 *path);
-extern void SMB2_open_free(struct smb_rqst *rqst);
-extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, u32 opcode,
- char *in_data, u32 indatalen, u32 maxoutlen,
- char **out_data, u32 *plen /* returned data len */);
-extern int SMB2_ioctl_init(struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid, u32 opcode,
- char *in_data, u32 indatalen,
- __u32 max_response_size);
-extern void SMB2_ioctl_free(struct smb_rqst *rqst);
-extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, bool watch_tree,
- u32 completion_filter, u32 max_out_data_len,
- char **out_data, u32 *plen /* returned data len */);
+int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ const struct nls_table *nls_cp);
+int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses);
+int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
+ struct cifs_tcon *tcon, const struct nls_table *cp);
+int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
+int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
+ __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf,
+ struct create_posix_rsp *posix, struct kvec *err_iov,
+ int *buftype);
+int SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, __u8 *oplock,
+ struct cifs_open_parms *oparms, __le16 *path);
+void SMB2_open_free(struct smb_rqst *rqst);
+int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, u32 opcode, char *in_data,
+ u32 indatalen, u32 max_out_data_len, char **out_data,
+ u32 *plen /* returned data len */);
+int SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, u64 persistent_fid,
+ u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen,
+ __u32 max_response_size);
+void SMB2_ioctl_free(struct smb_rqst *rqst);
+int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, bool watch_tree,
+ u32 completion_filter, u32 max_out_data_len,
+ char **out_data, u32 *plen /* returned data len */);
-extern int __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb2_file_network_open_info *pbuf);
-extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id);
-extern int SMB2_close_init(struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid,
- bool query_attrs);
-extern void SMB2_close_free(struct smb_rqst *rqst);
-extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id);
-extern int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
- struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- u64 persistent_file_id, u64 volatile_file_id);
-extern void SMB2_flush_free(struct smb_rqst *rqst);
-extern int SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen);
-extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id,
- struct smb2_file_all_info *data);
-extern int SMB2_query_info_init(struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid,
- u8 info_class, u8 info_type,
- u32 additional_info, size_t output_len,
- size_t input_len, void *input);
-extern void SMB2_query_info_free(struct smb_rqst *rqst);
-extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id,
- void **data, unsigned int *plen, u32 info);
-extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- __le64 *uniqueid);
-extern int smb2_async_readv(struct cifs_io_subrequest *rdata);
-extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, char **buf, int *buf_type);
-extern void smb2_async_writev(struct cifs_io_subrequest *wdata);
-extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, struct kvec *iov, int n_vec);
-extern int SMB2_echo(struct TCP_Server_Info *server);
-extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, int index,
- struct cifs_search_info *srch_inf);
-extern int SMB2_query_directory_init(unsigned int xid, struct cifs_tcon *tcon,
- struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid,
- int index, int info_level);
-extern void SMB2_query_directory_free(struct smb_rqst *rqst);
-extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, u32 pid,
- loff_t new_eof);
-extern int SMB2_set_info_init(struct cifs_tcon *tcon,
+int __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct smb2_file_network_open_info *pbuf);
+int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid);
+int SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, u64 persistent_fid,
+ u64 volatile_fid, bool query_attrs);
+void SMB2_close_free(struct smb_rqst *rqst);
+int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid);
+int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
+ struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ u64 persistent_fid, u64 volatile_fid);
+void SMB2_flush_free(struct smb_rqst *rqst);
+int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct smb2_file_all_info *data);
+int SMB2_query_info_init(struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server, struct smb_rqst *rqst,
+ u64 persistent_fid, u64 volatile_fid, u8 info_class,
+ u8 info_type, u32 additional_info, size_t output_len,
+ size_t input_len, void *input);
+void SMB2_query_info_free(struct smb_rqst *rqst);
+int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, void **data,
+ u32 *plen, u32 extra_info);
+int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid);
+int smb2_async_readv(struct cifs_io_subrequest *rdata);
+int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *buf_type);
+void smb2_async_writev(struct cifs_io_subrequest *wdata);
+int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec);
+int SMB2_echo(struct TCP_Server_Info *server);
+int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, int index,
+ struct cifs_search_info *srch_inf);
+int SMB2_query_directory_init(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server,
- struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid, u32 pid,
- u8 info_class, u8 info_type, u32 additional_info,
- void **data, unsigned int *size);
-extern void SMB2_set_info_free(struct smb_rqst *rqst);
-extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb_ntsd *pnntsd, int pacllen, int aclflag);
-extern int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb2_file_full_ea_info *buf, int len);
-extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid);
-extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
- const u64 persistent_fid, const u64 volatile_fid,
- const __u8 oplock_level);
-extern int smb2_handle_cancelled_close(struct cifs_tcon *tcon,
- __u64 persistent_fid,
- __u64 volatile_fid);
-extern int smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server);
+ struct smb_rqst *rqst, u64 persistent_fid,
+ u64 volatile_fid, int index, int info_level);
+void SMB2_query_directory_free(struct smb_rqst *rqst);
+int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, u32 pid,
+ loff_t new_eof);
+int SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, u64 persistent_fid,
+ u64 volatile_fid, u32 pid, u8 info_class, u8 info_type,
+ u32 additional_info, void **data, unsigned int *size);
+void SMB2_set_info_free(struct smb_rqst *rqst);
+int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, struct smb_ntsd *pnntsd,
+ int pacllen, int aclflag);
+int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct smb2_file_full_ea_info *buf, int len);
+int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid);
+int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ __u8 oplock_level);
+int smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
+ __u64 volatile_fid);
+int smb2_handle_cancelled_mid(struct mid_q_entry *mid,
+ struct TCP_Server_Info *server);
void smb2_cancelled_close_fid(struct work_struct *work);
-extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id,
- struct kstatfs *FSData);
-extern int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id,
- struct kstatfs *FSData);
-extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_file_id, u64 volatile_file_id, int lvl);
-extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
- const __u64 persist_fid, const __u64 volatile_fid,
- const __u32 pid, const __u64 length, const __u64 offset,
- const __u32 lockFlags, const bool wait);
-extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
- const __u64 persist_fid, const __u64 volatile_fid,
- const __u32 pid, const __u32 num_lock,
- struct smb2_lock_element *buf);
-extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
- __u8 *lease_key, const __le32 lease_state);
-extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
+int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct kstatfs *fsdata);
+int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, int level);
+int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u64 persist_fid, const __u64 volatile_fid,
+ const __u32 pid, const __u64 length, const __u64 offset,
+ const __u32 lock_flags, const bool wait);
+int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+ const __u64 persist_fid, const __u64 volatile_fid,
+ const __u32 pid, const __u32 num_lock,
+ struct smb2_lock_element *buf);
+int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
+ __u8 *lease_key, const __le32 lease_state);
+int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon);
-extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
- enum securityEnum);
-int smb2_parse_contexts(struct TCP_Server_Info *server,
- struct kvec *rsp_iov,
- __u16 *epoch,
- char *lease_key, __u8 *oplock,
+enum securityEnum smb2_select_sectype(struct TCP_Server_Info *server,
+ enum securityEnum requested);
+int smb2_parse_contexts(struct TCP_Server_Info *server, struct kvec *rsp_iov,
+ __u16 *epoch, char *lease_key, __u8 *oplock,
struct smb2_file_all_info *buf,
struct create_posix_rsp *posix);
-extern int smb3_encryption_required(const struct cifs_tcon *tcon);
-extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
- struct kvec *iov, unsigned int min_buf_size);
-extern int smb2_validate_and_copy_iov(unsigned int offset,
- unsigned int buffer_length,
- struct kvec *iov,
- unsigned int minbufsize, char *data);
-extern void smb2_copy_fs_info_to_kstatfs(
- struct smb2_fs_full_size_info *pfs_inf,
- struct kstatfs *kst);
-extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
-extern int smb311_update_preauth_hash(struct cifs_ses *ses,
- struct TCP_Server_Info *server,
- struct kvec *iov, int nvec);
-extern int smb2_query_info_compound(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *path, u32 desired_access,
- u32 class, u32 type, u32 output_len,
- struct kvec *rsp, int *buftype,
- struct cifs_sb_info *cifs_sb);
+int smb3_encryption_required(const struct cifs_tcon *tcon);
+int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
+ struct kvec *iov, unsigned int min_buf_size);
+int smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
+ struct kvec *iov, unsigned int minbufsize,
+ char *data);
+void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
+ struct kstatfs *kst);
+void smb311_update_preauth_hash(struct cifs_ses *ses,
+ struct TCP_Server_Info *server,
+ struct kvec *iov, int nvec);
+int smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *path, u32 desired_access, u32 class,
+ u32 type, u32 output_len, struct kvec *rsp,
+ int *buftype, struct cifs_sb_info *cifs_sb);
/* query path info from the server using SMB311 POSIX extensions*/
-int smb311_posix_query_path_info(const unsigned int xid,
- struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb,
- const char *full_path,
- struct cifs_open_info_data *data);
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end);
-int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
- struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, const char *symname);
-int smb2_make_nfs_node(unsigned int xid, struct inode *inode,
- struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev);
+int smb2_rename_pending_delete(const char *full_path, struct dentry *dentry,
+ const unsigned int xid);
#endif /* _SMB2PROTO_H */
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 475b36c27f65..41009039b4cb 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -19,6 +19,9 @@
#include <linux/mempool.h>
#include <linux/highmem.h>
#include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
+#include <crypto/sha2.h>
+#include <crypto/utils.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "smb2proto.h"
@@ -26,53 +29,6 @@
#include "../common/smb2status.h"
#include "smb2glob.h"
-static int
-smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
- struct cifs_secmech *p = &server->secmech;
- int rc;
-
- rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256);
- if (rc)
- goto err;
-
- rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac);
- if (rc)
- goto err;
-
- return 0;
-err:
- cifs_free_hash(&p->hmacsha256);
- return rc;
-}
-
-int
-smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
- struct cifs_secmech *p = &server->secmech;
- int rc = 0;
-
- rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256);
- if (rc)
- return rc;
-
- rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac);
- if (rc)
- goto err;
-
- rc = cifs_alloc_hash("sha512", &p->sha512);
- if (rc)
- goto err;
-
- return 0;
-
-err:
- cifs_free_hash(&p->aes_cmac);
- cifs_free_hash(&p->hmacsha256);
- return rc;
-}
-
-
static
int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
{
@@ -191,7 +147,7 @@ static int smb2_get_sign_key(struct TCP_Server_Info *server,
memcpy(key, ses->auth_key.response,
SMB2_NTLMV2_SESSKEY_SIZE);
} else {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_no_auth_key);
}
break;
default:
@@ -240,11 +196,6 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
return NULL;
}
tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid);
- if (!tcon) {
- spin_unlock(&cifs_tcp_ses_lock);
- cifs_put_smb_ses(ses);
- return NULL;
- }
spin_unlock(&cifs_tcp_ses_lock);
/* tcon already has a ref to ses, so we don't need ses anymore */
cifs_put_smb_ses(ses);
@@ -252,16 +203,14 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
return tcon;
}
-int
-smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
- bool allocate_crypto)
+static int
+smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
int rc;
unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
- unsigned char *sigptr = smb2_signature;
struct kvec *iov = rqst->rq_iov;
struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
- struct shash_desc *shash = NULL;
+ struct hmac_sha256_ctx hmac_ctx;
struct smb_rqst drqst;
__u64 sid = le64_to_cpu(shdr->SessionId);
u8 key[SMB2_NTLMV2_SESSKEY_SIZE];
@@ -276,30 +225,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
- if (allocate_crypto) {
- rc = cifs_alloc_hash("hmac(sha256)", &shash);
- if (rc) {
- cifs_server_dbg(VFS,
- "%s: sha256 alloc failed\n", __func__);
- goto out;
- }
- } else {
- shash = server->secmech.hmacsha256;
- }
-
- rc = crypto_shash_setkey(shash->tfm, key, sizeof(key));
- if (rc) {
- cifs_server_dbg(VFS,
- "%s: Could not update with response\n",
- __func__);
- goto out;
- }
-
- rc = crypto_shash_init(shash);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not init sha256", __func__);
- goto out;
- }
+ hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key));
/*
* For SMB2+, __cifs_calc_signature() expects to sign only the actual
@@ -310,107 +236,50 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
*/
drqst = *rqst;
if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
- rc = crypto_shash_update(shash, iov[0].iov_base,
- iov[0].iov_len);
- if (rc) {
- cifs_server_dbg(VFS,
- "%s: Could not update with payload\n",
- __func__);
- goto out;
- }
+ hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len);
drqst.rq_iov++;
drqst.rq_nvec--;
}
- rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
+ rc = __cifs_calc_signature(
+ &drqst, server, smb2_signature,
+ &(struct cifs_calc_sig_ctx){ .hmac = &hmac_ctx });
if (!rc)
- memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+ memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE);
-out:
- if (allocate_crypto)
- cifs_free_hash(&shash);
return rc;
}
-static int generate_key(struct cifs_ses *ses, struct kvec label,
- struct kvec context, __u8 *key, unsigned int key_size)
+static void generate_key(struct cifs_ses *ses, struct kvec label,
+ struct kvec context, __u8 *key, unsigned int key_size)
{
unsigned char zero = 0x0;
__u8 i[4] = {0, 0, 0, 1};
__u8 L128[4] = {0, 0, 0, 128};
__u8 L256[4] = {0, 0, 1, 0};
- int rc = 0;
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
- unsigned char *hashptr = prfhash;
struct TCP_Server_Info *server = ses->server;
+ struct hmac_sha256_ctx hmac_ctx;
memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
memset(key, 0x0, key_size);
- rc = smb3_crypto_shash_allocate(server);
- if (rc) {
- cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm,
- ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_init(server->secmech.hmacsha256);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_update(server->secmech.hmacsha256, i, 4);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_update(server->secmech.hmacsha256, label.iov_base, label.iov_len);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_update(server->secmech.hmacsha256, &zero, 1);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_update(server->secmech.hmacsha256, context.iov_base, context.iov_len);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__);
- goto smb3signkey_ret;
- }
+ hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response,
+ SMB2_NTLMV2_SESSKEY_SIZE);
+ hmac_sha256_update(&hmac_ctx, i, 4);
+ hmac_sha256_update(&hmac_ctx, label.iov_base, label.iov_len);
+ hmac_sha256_update(&hmac_ctx, &zero, 1);
+ hmac_sha256_update(&hmac_ctx, context.iov_base, context.iov_len);
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) {
- rc = crypto_shash_update(server->secmech.hmacsha256, L256, 4);
+ hmac_sha256_update(&hmac_ctx, L256, 4);
} else {
- rc = crypto_shash_update(server->secmech.hmacsha256, L128, 4);
- }
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__);
- goto smb3signkey_ret;
- }
-
- rc = crypto_shash_final(server->secmech.hmacsha256, hashptr);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
- goto smb3signkey_ret;
+ hmac_sha256_update(&hmac_ctx, L128, 4);
}
+ hmac_sha256_final(&hmac_ctx, prfhash);
- memcpy(key, hashptr, key_size);
-
-smb3signkey_ret:
- return rc;
+ memcpy(key, prfhash, key_size);
}
struct derivation {
@@ -429,7 +298,6 @@ generate_smb3signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct derivation_triplet *ptriplet)
{
- int rc;
bool is_binding = false;
int chan_index = 0;
@@ -460,19 +328,14 @@ generate_smb3signingkey(struct cifs_ses *ses,
*/
if (is_binding) {
- rc = generate_key(ses, ptriplet->signing.label,
- ptriplet->signing.context,
- ses->chans[chan_index].signkey,
- SMB3_SIGN_KEY_SIZE);
- if (rc)
- return rc;
+ generate_key(ses, ptriplet->signing.label,
+ ptriplet->signing.context,
+ ses->chans[chan_index].signkey,
+ SMB3_SIGN_KEY_SIZE);
} else {
- rc = generate_key(ses, ptriplet->signing.label,
- ptriplet->signing.context,
- ses->smb3signingkey,
- SMB3_SIGN_KEY_SIZE);
- if (rc)
- return rc;
+ generate_key(ses, ptriplet->signing.label,
+ ptriplet->signing.context,
+ ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
/* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock);
@@ -480,18 +343,12 @@ generate_smb3signingkey(struct cifs_ses *ses,
SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
- rc = generate_key(ses, ptriplet->encryption.label,
- ptriplet->encryption.context,
- ses->smb3encryptionkey,
- SMB3_ENC_DEC_KEY_SIZE);
- if (rc)
- return rc;
- rc = generate_key(ses, ptriplet->decryption.label,
- ptriplet->decryption.context,
- ses->smb3decryptionkey,
- SMB3_ENC_DEC_KEY_SIZE);
- if (rc)
- return rc;
+ generate_key(ses, ptriplet->encryption.label,
+ ptriplet->encryption.context,
+ ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE);
+ generate_key(ses, ptriplet->decryption.label,
+ ptriplet->decryption.context,
+ ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
}
#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
@@ -520,7 +377,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3decryptionkey);
}
#endif
- return rc;
+ return 0;
}
int
@@ -581,52 +438,37 @@ generate_smb311signingkey(struct cifs_ses *ses,
return generate_smb3signingkey(ses, server, &triplet);
}
-int
-smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
- bool allocate_crypto)
+static int
+smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
int rc;
unsigned char smb3_signature[SMB2_CMACAES_SIZE];
- unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov;
struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
- struct shash_desc *shash = NULL;
+ struct aes_cmac_key cmac_key;
+ struct aes_cmac_ctx cmac_ctx;
struct smb_rqst drqst;
u8 key[SMB3_SIGN_KEY_SIZE];
+ if (server->vals->protocol_id <= SMB21_PROT_ID)
+ return smb2_calc_signature(rqst, server);
+
rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
if (unlikely(rc)) {
cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
return rc;
}
- if (allocate_crypto) {
- rc = cifs_alloc_hash("cmac(aes)", &shash);
- if (rc)
- return rc;
- } else {
- shash = server->secmech.aes_cmac;
- }
-
memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
- rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE);
+ rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
if (rc) {
cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
- goto out;
+ return rc;
}
- /*
- * we already allocate aes_cmac when we init smb3 signing key,
- * so unlike smb2 case we do not have to check here if secmech are
- * initialized
- */
- rc = crypto_shash_init(shash);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
- goto out;
- }
+ aes_cmac_init(&cmac_ctx, &cmac_key);
/*
* For SMB2+, __cifs_calc_signature() expects to sign only the actual
@@ -637,24 +479,16 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
*/
drqst = *rqst;
if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
- rc = crypto_shash_update(shash, iov[0].iov_base,
- iov[0].iov_len);
- if (rc) {
- cifs_server_dbg(VFS, "%s: Could not update with payload\n",
- __func__);
- goto out;
- }
+ aes_cmac_update(&cmac_ctx, iov[0].iov_base, iov[0].iov_len);
drqst.rq_iov++;
drqst.rq_nvec--;
}
- rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
+ rc = __cifs_calc_signature(
+ &drqst, server, smb3_signature,
+ &(struct cifs_calc_sig_ctx){ .cmac = &cmac_ctx });
if (!rc)
- memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
-
-out:
- if (allocate_crypto)
- cifs_free_hash(&shash);
+ memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
return rc;
}
@@ -662,7 +496,6 @@ out:
static int
smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
- int rc = 0;
struct smb2_hdr *shdr;
struct smb2_sess_setup_req *ssr;
bool is_binding;
@@ -689,9 +522,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return 0;
}
- rc = server->ops->calc_signature(rqst, server, false);
-
- return rc;
+ return smb3_calc_signature(rqst, server);
}
int
@@ -727,12 +558,13 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
- rc = server->ops->calc_signature(rqst, server, true);
+ rc = smb3_calc_signature(rqst, server);
if (rc)
return rc;
- if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) {
+ if (crypto_memneq(server_response_sig, shdr->Signature,
+ SMB2_SIGNATURE_SIZE)) {
cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n",
shdr->Command, shdr->MessageId);
return -EACCES;
@@ -768,15 +600,15 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
return NULL;
}
- temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
+ temp = mempool_alloc(&cifs_mid_pool, GFP_NOFS);
memset(temp, 0, sizeof(struct mid_q_entry));
- kref_init(&temp->refcount);
+ refcount_set(&temp->refcount, 1);
+ spin_lock_init(&temp->mid_lock);
temp->mid = le64_to_cpu(shdr->MessageId);
temp->credits = credits > 0 ? credits : 1;
temp->pid = current->pid;
temp->command = shdr->Command; /* Always LE */
temp->when_alloc = jiffies;
- temp->server = server;
/*
* The default is for the mid to be synchronous, so the
@@ -799,50 +631,42 @@ static int
smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
struct smb2_hdr *shdr, struct mid_q_entry **mid)
{
- spin_lock(&server->srv_lock);
- if (server->tcpStatus == CifsExiting) {
- spin_unlock(&server->srv_lock);
+ switch (READ_ONCE(server->tcpStatus)) {
+ case CifsExiting:
return -ENOENT;
- }
-
- if (server->tcpStatus == CifsNeedReconnect) {
- spin_unlock(&server->srv_lock);
+ case CifsNeedReconnect:
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
return -EAGAIN;
- }
-
- if (server->tcpStatus == CifsNeedNegotiate &&
- shdr->Command != SMB2_NEGOTIATE) {
- spin_unlock(&server->srv_lock);
- return -EAGAIN;
- }
- spin_unlock(&server->srv_lock);
-
- spin_lock(&ses->ses_lock);
- if (ses->ses_status == SES_NEW) {
- if ((shdr->Command != SMB2_SESSION_SETUP) &&
- (shdr->Command != SMB2_NEGOTIATE)) {
- spin_unlock(&ses->ses_lock);
+ case CifsNeedNegotiate:
+ if (shdr->Command != SMB2_NEGOTIATE)
return -EAGAIN;
- }
- /* else ok - we are setting up session */
+ break;
+ default:
+ break;
}
- if (ses->ses_status == SES_EXITING) {
- if (shdr->Command != SMB2_LOGOFF) {
- spin_unlock(&ses->ses_lock);
+ switch (READ_ONCE(ses->ses_status)) {
+ case SES_NEW:
+ if (shdr->Command != SMB2_SESSION_SETUP &&
+ shdr->Command != SMB2_NEGOTIATE)
+ return -EAGAIN;
+ /* else ok - we are setting up session */
+ break;
+ case SES_EXITING:
+ if (shdr->Command != SMB2_LOGOFF)
return -EAGAIN;
- }
/* else ok - we are shutting down the session */
+ break;
+ default:
+ break;
}
- spin_unlock(&ses->ses_lock);
*mid = smb2_mid_entry_alloc(shdr, server);
if (*mid == NULL)
return -ENOMEM;
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_add_tail(&(*mid)->qhead, &server->pending_mid_q);
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
return 0;
}
@@ -893,7 +717,7 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
rc = smb2_sign_rqst(rqst, server);
if (rc) {
revert_current_mid_from_hdr(server, shdr);
- delete_mid(mid);
+ delete_mid(server, mid);
return ERR_PTR(rc);
}
@@ -927,7 +751,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
rc = smb2_sign_rqst(rqst, server);
if (rc) {
revert_current_mid_from_hdr(server, shdr);
- release_mid(mid);
+ release_mid(server, mid);
return ERR_PTR(rc);
}
diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index b0b7254661e9..75f9f91a7ec9 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -4,54 +4,12 @@
*
* Author(s): Long Li <longli@microsoft.com>
*/
-#include <linux/module.h>
-#include <linux/highmem.h>
-#include <linux/folio_queue.h>
+
#include "smbdirect.h"
#include "cifs_debug.h"
#include "cifsproto.h"
#include "smb2proto.h"
-
-static struct smbd_response *get_empty_queue_buffer(
- struct smbd_connection *info);
-static struct smbd_response *get_receive_buffer(
- struct smbd_connection *info);
-static void put_receive_buffer(
- struct smbd_connection *info,
- struct smbd_response *response);
-static int allocate_receive_buffers(struct smbd_connection *info, int num_buf);
-static void destroy_receive_buffers(struct smbd_connection *info);
-
-static void put_empty_packet(
- struct smbd_connection *info, struct smbd_response *response);
-static void enqueue_reassembly(
- struct smbd_connection *info,
- struct smbd_response *response, int data_length);
-static struct smbd_response *_get_first_reassembly(
- struct smbd_connection *info);
-
-static int smbd_post_recv(
- struct smbd_connection *info,
- struct smbd_response *response);
-
-static int smbd_post_send_empty(struct smbd_connection *info);
-
-static void destroy_mr_list(struct smbd_connection *info);
-static int allocate_mr_list(struct smbd_connection *info);
-
-struct smb_extract_to_rdma {
- struct ib_sge *sge;
- unsigned int nr_sge;
- unsigned int max_sge;
- struct ib_device *device;
- u32 local_dma_lkey;
- enum dma_data_direction direction;
-};
-static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len,
- struct smb_extract_to_rdma *rdma);
-
-/* SMBD version number */
-#define SMBD_V1 0x0100
+#include "../smbdirect/public.h"
/* Port numbers for SMBD transport */
#define SMB_PORT 445
@@ -63,9 +21,8 @@ static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len,
/* SMBD negotiation timeout in seconds */
#define SMBD_NEGOTIATE_TIMEOUT 120
-/* SMBD minimum receive size and fragmented sized defined in [MS-SMBD] */
-#define SMBD_MIN_RECEIVE_SIZE 128
-#define SMBD_MIN_FRAGMENTED_SIZE 131072
+/* The timeout to wait for a keepalive message from peer in seconds */
+#define KEEPALIVE_RECV_TIMEOUT 5
/*
* Default maximum number of RDMA read/write outstanding on this connection
@@ -73,11 +30,6 @@ static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len,
*/
#define SMBD_CM_RESPONDER_RESOURCES 32
-/* Maximum number of retries on data transfer operations */
-#define SMBD_CM_RETRY 6
-/* No need to retry on Receiver Not Ready since SMBD manages credits */
-#define SMBD_CM_RNR_RETRY 0
-
/*
* User configurable initial values per SMBD transport connection
* as defined in [MS-SMBD] 3.1.1.1
@@ -92,8 +44,23 @@ int smbd_send_credit_target = 255;
/* The maximum single message size can be sent to remote peer */
int smbd_max_send_size = 1364;
-/* The maximum fragmented upper-layer payload receive size supported */
-int smbd_max_fragmented_recv_size = 1024 * 1024;
+/*
+ * The maximum fragmented upper-layer payload receive size supported
+ *
+ * Assume max_payload_per_credit is
+ * smbd_max_receive_size - 24 = 1340
+ *
+ * The maximum number would be
+ * smbd_receive_credit_max * max_payload_per_credit
+ *
+ * 1340 * 255 = 341700 (0x536C4)
+ *
+ * The minimum value from the spec is 131072 (0x20000)
+ *
+ * For now we use the logic we used in ksmbd before:
+ * (1364 * 255) / 2 = 173910 (0x2A756)
+ */
+int smbd_max_fragmented_recv_size = (1364 * 255) / 2;
/* The maximum single-message size which can be received */
int smbd_max_receive_size = 1364;
@@ -138,6 +105,43 @@ module_param(smbd_logging_level, uint, 0644);
MODULE_PARM_DESC(smbd_logging_level,
"Logging level for SMBD transport, 0 (default): error, 1: info");
+static bool smbd_logging_needed(struct smbdirect_socket *sc,
+ void *private_ptr,
+ unsigned int lvl,
+ unsigned int cls)
+{
+#define BUILD_BUG_SAME(x) BUILD_BUG_ON(x != SMBDIRECT_LOG_ ##x)
+ BUILD_BUG_SAME(ERR);
+ BUILD_BUG_SAME(INFO);
+#undef BUILD_BUG_SAME
+#define BUILD_BUG_SAME(x) BUILD_BUG_ON(x != SMBDIRECT_ ##x)
+ BUILD_BUG_SAME(LOG_OUTGOING);
+ BUILD_BUG_SAME(LOG_INCOMING);
+ BUILD_BUG_SAME(LOG_READ);
+ BUILD_BUG_SAME(LOG_WRITE);
+ BUILD_BUG_SAME(LOG_RDMA_SEND);
+ BUILD_BUG_SAME(LOG_RDMA_RECV);
+ BUILD_BUG_SAME(LOG_KEEP_ALIVE);
+ BUILD_BUG_SAME(LOG_RDMA_EVENT);
+ BUILD_BUG_SAME(LOG_RDMA_MR);
+#undef BUILD_BUG_SAME
+
+ if (lvl <= smbd_logging_level || cls & smbd_logging_class)
+ return true;
+ return false;
+}
+
+static void smbd_logging_vaprintf(struct smbdirect_socket *sc,
+ const char *func,
+ unsigned int line,
+ void *private_ptr,
+ unsigned int lvl,
+ unsigned int cls,
+ struct va_format *vaf)
+{
+ cifs_dbg(VFS, "%s:%u %pV", func, line, vaf);
+}
+
#define log_rdma(level, class, fmt, args...) \
do { \
if (level <= smbd_logging_level || class & smbd_logging_class) \
@@ -161,1124 +165,34 @@ do { \
#define log_rdma_mr(level, fmt, args...) \
log_rdma(level, LOG_RDMA_MR, fmt, ##args)
-static void smbd_disconnect_rdma_work(struct work_struct *work)
-{
- struct smbd_connection *info =
- container_of(work, struct smbd_connection, disconnect_work);
-
- if (info->transport_status == SMBD_CONNECTED) {
- info->transport_status = SMBD_DISCONNECTING;
- rdma_disconnect(info->id);
- }
-}
-
-static void smbd_disconnect_rdma_connection(struct smbd_connection *info)
-{
- queue_work(info->workqueue, &info->disconnect_work);
-}
-
-/* Upcall from RDMA CM */
-static int smbd_conn_upcall(
- struct rdma_cm_id *id, struct rdma_cm_event *event)
-{
- struct smbd_connection *info = id->context;
-
- log_rdma_event(INFO, "event=%d status=%d\n",
- event->event, event->status);
-
- switch (event->event) {
- case RDMA_CM_EVENT_ADDR_RESOLVED:
- case RDMA_CM_EVENT_ROUTE_RESOLVED:
- info->ri_rc = 0;
- complete(&info->ri_done);
- break;
-
- case RDMA_CM_EVENT_ADDR_ERROR:
- info->ri_rc = -EHOSTUNREACH;
- complete(&info->ri_done);
- break;
-
- case RDMA_CM_EVENT_ROUTE_ERROR:
- info->ri_rc = -ENETUNREACH;
- complete(&info->ri_done);
- break;
-
- case RDMA_CM_EVENT_ESTABLISHED:
- log_rdma_event(INFO, "connected event=%d\n", event->event);
- info->transport_status = SMBD_CONNECTED;
- wake_up_interruptible(&info->conn_wait);
- break;
-
- case RDMA_CM_EVENT_CONNECT_ERROR:
- case RDMA_CM_EVENT_UNREACHABLE:
- case RDMA_CM_EVENT_REJECTED:
- log_rdma_event(INFO, "connecting failed event=%d\n", event->event);
- info->transport_status = SMBD_DISCONNECTED;
- wake_up_interruptible(&info->conn_wait);
- break;
-
- case RDMA_CM_EVENT_DEVICE_REMOVAL:
- case RDMA_CM_EVENT_DISCONNECTED:
- /* This happens when we fail the negotiation */
- if (info->transport_status == SMBD_NEGOTIATE_FAILED) {
- info->transport_status = SMBD_DISCONNECTED;
- wake_up(&info->conn_wait);
- break;
- }
-
- info->transport_status = SMBD_DISCONNECTED;
- wake_up_interruptible(&info->disconn_wait);
- wake_up_interruptible(&info->wait_reassembly_queue);
- wake_up_interruptible_all(&info->wait_send_queue);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Upcall from RDMA QP */
-static void
-smbd_qp_async_error_upcall(struct ib_event *event, void *context)
-{
- struct smbd_connection *info = context;
-
- log_rdma_event(ERR, "%s on device %s info %p\n",
- ib_event_msg(event->event), event->device->name, info);
-
- switch (event->event) {
- case IB_EVENT_CQ_ERR:
- case IB_EVENT_QP_FATAL:
- smbd_disconnect_rdma_connection(info);
- break;
-
- default:
- break;
- }
-}
-
-static inline void *smbd_request_payload(struct smbd_request *request)
-{
- return (void *)request->packet;
-}
-
-static inline void *smbd_response_payload(struct smbd_response *response)
-{
- return (void *)response->packet;
-}
-
-/* Called when a RDMA send is done */
-static void send_done(struct ib_cq *cq, struct ib_wc *wc)
-{
- int i;
- struct smbd_request *request =
- container_of(wc->wr_cqe, struct smbd_request, cqe);
-
- log_rdma_send(INFO, "smbd_request 0x%p completed wc->status=%d\n",
- request, wc->status);
-
- if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) {
- log_rdma_send(ERR, "wc->status=%d wc->opcode=%d\n",
- wc->status, wc->opcode);
- smbd_disconnect_rdma_connection(request->info);
- }
-
- for (i = 0; i < request->num_sge; i++)
- ib_dma_unmap_single(request->info->id->device,
- request->sge[i].addr,
- request->sge[i].length,
- DMA_TO_DEVICE);
-
- if (atomic_dec_and_test(&request->info->send_pending))
- wake_up(&request->info->wait_send_pending);
-
- wake_up(&request->info->wait_post_send);
-
- mempool_free(request, request->info->request_mempool);
-}
-
-static void dump_smbd_negotiate_resp(struct smbd_negotiate_resp *resp)
-{
- log_rdma_event(INFO, "resp message min_version %u max_version %u negotiated_version %u credits_requested %u credits_granted %u status %u max_readwrite_size %u preferred_send_size %u max_receive_size %u max_fragmented_size %u\n",
- resp->min_version, resp->max_version,
- resp->negotiated_version, resp->credits_requested,
- resp->credits_granted, resp->status,
- resp->max_readwrite_size, resp->preferred_send_size,
- resp->max_receive_size, resp->max_fragmented_size);
-}
-
-/*
- * Process a negotiation response message, according to [MS-SMBD]3.1.5.7
- * response, packet_length: the negotiation response message
- * return value: true if negotiation is a success, false if failed
- */
-static bool process_negotiation_response(
- struct smbd_response *response, int packet_length)
-{
- struct smbd_connection *info = response->info;
- struct smbd_negotiate_resp *packet = smbd_response_payload(response);
-
- if (packet_length < sizeof(struct smbd_negotiate_resp)) {
- log_rdma_event(ERR,
- "error: packet_length=%d\n", packet_length);
- return false;
- }
-
- if (le16_to_cpu(packet->negotiated_version) != SMBD_V1) {
- log_rdma_event(ERR, "error: negotiated_version=%x\n",
- le16_to_cpu(packet->negotiated_version));
- return false;
- }
- info->protocol = le16_to_cpu(packet->negotiated_version);
-
- if (packet->credits_requested == 0) {
- log_rdma_event(ERR, "error: credits_requested==0\n");
- return false;
- }
- info->receive_credit_target = le16_to_cpu(packet->credits_requested);
-
- if (packet->credits_granted == 0) {
- log_rdma_event(ERR, "error: credits_granted==0\n");
- return false;
- }
- atomic_set(&info->send_credits, le16_to_cpu(packet->credits_granted));
-
- atomic_set(&info->receive_credits, 0);
-
- if (le32_to_cpu(packet->preferred_send_size) > info->max_receive_size) {
- log_rdma_event(ERR, "error: preferred_send_size=%d\n",
- le32_to_cpu(packet->preferred_send_size));
- return false;
- }
- info->max_receive_size = le32_to_cpu(packet->preferred_send_size);
-
- if (le32_to_cpu(packet->max_receive_size) < SMBD_MIN_RECEIVE_SIZE) {
- log_rdma_event(ERR, "error: max_receive_size=%d\n",
- le32_to_cpu(packet->max_receive_size));
- return false;
- }
- info->max_send_size = min_t(int, info->max_send_size,
- le32_to_cpu(packet->max_receive_size));
-
- if (le32_to_cpu(packet->max_fragmented_size) <
- SMBD_MIN_FRAGMENTED_SIZE) {
- log_rdma_event(ERR, "error: max_fragmented_size=%d\n",
- le32_to_cpu(packet->max_fragmented_size));
- return false;
- }
- info->max_fragmented_send_size =
- le32_to_cpu(packet->max_fragmented_size);
- info->rdma_readwrite_threshold =
- rdma_readwrite_threshold > info->max_fragmented_send_size ?
- info->max_fragmented_send_size :
- rdma_readwrite_threshold;
-
-
- info->max_readwrite_size = min_t(u32,
- le32_to_cpu(packet->max_readwrite_size),
- info->max_frmr_depth * PAGE_SIZE);
- info->max_frmr_depth = info->max_readwrite_size / PAGE_SIZE;
-
- return true;
-}
-
-static void smbd_post_send_credits(struct work_struct *work)
+static int smbd_post_send_full_iter(struct smbdirect_socket *sc,
+ struct smbdirect_send_batch *batch,
+ struct iov_iter *iter,
+ u32 remaining_data_length)
{
- int ret = 0;
- int use_receive_queue = 1;
- int rc;
- struct smbd_response *response;
- struct smbd_connection *info =
- container_of(work, struct smbd_connection,
- post_send_credits_work);
-
- if (info->transport_status != SMBD_CONNECTED) {
- wake_up(&info->wait_receive_queues);
- return;
- }
-
- if (info->receive_credit_target >
- atomic_read(&info->receive_credits)) {
- while (true) {
- if (use_receive_queue)
- response = get_receive_buffer(info);
- else
- response = get_empty_queue_buffer(info);
- if (!response) {
- /* now switch to empty packet queue */
- if (use_receive_queue) {
- use_receive_queue = 0;
- continue;
- } else
- break;
- }
-
- response->type = SMBD_TRANSFER_DATA;
- response->first_segment = false;
- rc = smbd_post_recv(info, response);
- if (rc) {
- log_rdma_recv(ERR,
- "post_recv failed rc=%d\n", rc);
- put_receive_buffer(info, response);
- break;
- }
+ int bytes = 0;
- ret++;
- }
- }
-
- spin_lock(&info->lock_new_credits_offered);
- info->new_credits_offered += ret;
- spin_unlock(&info->lock_new_credits_offered);
-
- /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */
- info->send_immediate = true;
- if (atomic_read(&info->receive_credits) <
- info->receive_credit_target - 1) {
- if (info->keep_alive_requested == KEEP_ALIVE_PENDING ||
- info->send_immediate) {
- log_keep_alive(INFO, "send an empty message\n");
- smbd_post_send_empty(info);
- }
- }
-}
-
-/* Called from softirq, when recv is done */
-static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
-{
- struct smbd_data_transfer *data_transfer;
- struct smbd_response *response =
- container_of(wc->wr_cqe, struct smbd_response, cqe);
- struct smbd_connection *info = response->info;
- int data_length = 0;
-
- log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n",
- response, response->type, wc->status, wc->opcode,
- wc->byte_len, wc->pkey_index);
-
- if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) {
- log_rdma_recv(INFO, "wc->status=%d opcode=%d\n",
- wc->status, wc->opcode);
- smbd_disconnect_rdma_connection(info);
- goto error;
- }
-
- ib_dma_sync_single_for_cpu(
- wc->qp->device,
- response->sge.addr,
- response->sge.length,
- DMA_FROM_DEVICE);
-
- switch (response->type) {
- /* SMBD negotiation response */
- case SMBD_NEGOTIATE_RESP:
- dump_smbd_negotiate_resp(smbd_response_payload(response));
- info->full_packet_received = true;
- info->negotiate_done =
- process_negotiation_response(response, wc->byte_len);
- complete(&info->negotiate_completion);
- break;
-
- /* SMBD data transfer packet */
- case SMBD_TRANSFER_DATA:
- data_transfer = smbd_response_payload(response);
- data_length = le32_to_cpu(data_transfer->data_length);
-
- /*
- * If this is a packet with data playload place the data in
- * reassembly queue and wake up the reading thread
- */
- if (data_length) {
- if (info->full_packet_received)
- response->first_segment = true;
-
- if (le32_to_cpu(data_transfer->remaining_data_length))
- info->full_packet_received = false;
- else
- info->full_packet_received = true;
-
- enqueue_reassembly(
- info,
- response,
- data_length);
- } else
- put_empty_packet(info, response);
-
- if (data_length)
- wake_up_interruptible(&info->wait_reassembly_queue);
-
- atomic_dec(&info->receive_credits);
- info->receive_credit_target =
- le16_to_cpu(data_transfer->credits_requested);
- if (le16_to_cpu(data_transfer->credits_granted)) {
- atomic_add(le16_to_cpu(data_transfer->credits_granted),
- &info->send_credits);
- /*
- * We have new send credits granted from remote peer
- * If any sender is waiting for credits, unblock it
- */
- wake_up_interruptible(&info->wait_send_queue);
- }
-
- log_incoming(INFO, "data flags %d data_offset %d data_length %d remaining_data_length %d\n",
- le16_to_cpu(data_transfer->flags),
- le32_to_cpu(data_transfer->data_offset),
- le32_to_cpu(data_transfer->data_length),
- le32_to_cpu(data_transfer->remaining_data_length));
-
- /* Send a KEEP_ALIVE response right away if requested */
- info->keep_alive_requested = KEEP_ALIVE_NONE;
- if (le16_to_cpu(data_transfer->flags) &
- SMB_DIRECT_RESPONSE_REQUESTED) {
- info->keep_alive_requested = KEEP_ALIVE_PENDING;
- }
-
- return;
-
- default:
- log_rdma_recv(ERR,
- "unexpected response type=%d\n", response->type);
- }
-
-error:
- put_receive_buffer(info, response);
-}
-
-static struct rdma_cm_id *smbd_create_id(
- struct smbd_connection *info,
- struct sockaddr *dstaddr, int port)
-{
- struct rdma_cm_id *id;
- int rc;
- __be16 *sport;
-
- id = rdma_create_id(&init_net, smbd_conn_upcall, info,
- RDMA_PS_TCP, IB_QPT_RC);
- if (IS_ERR(id)) {
- rc = PTR_ERR(id);
- log_rdma_event(ERR, "rdma_create_id() failed %i\n", rc);
- return id;
- }
-
- if (dstaddr->sa_family == AF_INET6)
- sport = &((struct sockaddr_in6 *)dstaddr)->sin6_port;
- else
- sport = &((struct sockaddr_in *)dstaddr)->sin_port;
-
- *sport = htons(port);
-
- init_completion(&info->ri_done);
- info->ri_rc = -ETIMEDOUT;
-
- rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)dstaddr,
- RDMA_RESOLVE_TIMEOUT);
- if (rc) {
- log_rdma_event(ERR, "rdma_resolve_addr() failed %i\n", rc);
- goto out;
- }
- rc = wait_for_completion_interruptible_timeout(
- &info->ri_done, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT));
- /* e.g. if interrupted returns -ERESTARTSYS */
- if (rc < 0) {
- log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc);
- goto out;
- }
- rc = info->ri_rc;
- if (rc) {
- log_rdma_event(ERR, "rdma_resolve_addr() completed %i\n", rc);
- goto out;
- }
-
- info->ri_rc = -ETIMEDOUT;
- rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
- if (rc) {
- log_rdma_event(ERR, "rdma_resolve_route() failed %i\n", rc);
- goto out;
- }
- rc = wait_for_completion_interruptible_timeout(
- &info->ri_done, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT));
- /* e.g. if interrupted returns -ERESTARTSYS */
- if (rc < 0) {
- log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc);
- goto out;
- }
- rc = info->ri_rc;
- if (rc) {
- log_rdma_event(ERR, "rdma_resolve_route() completed %i\n", rc);
- goto out;
- }
-
- return id;
-
-out:
- rdma_destroy_id(id);
- return ERR_PTR(rc);
-}
-
-/*
- * Test if FRWR (Fast Registration Work Requests) is supported on the device
- * This implementation requires FRWR on RDMA read/write
- * return value: true if it is supported
- */
-static bool frwr_is_supported(struct ib_device_attr *attrs)
-{
- if (!(attrs->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS))
- return false;
- if (attrs->max_fast_reg_page_list_len == 0)
- return false;
- return true;
-}
-
-static int smbd_ia_open(
- struct smbd_connection *info,
- struct sockaddr *dstaddr, int port)
-{
- int rc;
-
- info->id = smbd_create_id(info, dstaddr, port);
- if (IS_ERR(info->id)) {
- rc = PTR_ERR(info->id);
- goto out1;
- }
-
- if (!frwr_is_supported(&info->id->device->attrs)) {
- log_rdma_event(ERR, "Fast Registration Work Requests (FRWR) is not supported\n");
- log_rdma_event(ERR, "Device capability flags = %llx max_fast_reg_page_list_len = %u\n",
- info->id->device->attrs.device_cap_flags,
- info->id->device->attrs.max_fast_reg_page_list_len);
- rc = -EPROTONOSUPPORT;
- goto out2;
- }
- info->max_frmr_depth = min_t(int,
- smbd_max_frmr_depth,
- info->id->device->attrs.max_fast_reg_page_list_len);
- info->mr_type = IB_MR_TYPE_MEM_REG;
- if (info->id->device->attrs.kernel_cap_flags & IBK_SG_GAPS_REG)
- info->mr_type = IB_MR_TYPE_SG_GAPS;
-
- info->pd = ib_alloc_pd(info->id->device, 0);
- if (IS_ERR(info->pd)) {
- rc = PTR_ERR(info->pd);
- log_rdma_event(ERR, "ib_alloc_pd() returned %d\n", rc);
- goto out2;
- }
-
- return 0;
-
-out2:
- rdma_destroy_id(info->id);
- info->id = NULL;
-
-out1:
- return rc;
-}
-
-/*
- * Send a negotiation request message to the peer
- * The negotiation procedure is in [MS-SMBD] 3.1.5.2 and 3.1.5.3
- * After negotiation, the transport is connected and ready for
- * carrying upper layer SMB payload
- */
-static int smbd_post_send_negotiate_req(struct smbd_connection *info)
-{
- struct ib_send_wr send_wr;
- int rc = -ENOMEM;
- struct smbd_request *request;
- struct smbd_negotiate_req *packet;
-
- request = mempool_alloc(info->request_mempool, GFP_KERNEL);
- if (!request)
- return rc;
-
- request->info = info;
-
- packet = smbd_request_payload(request);
- packet->min_version = cpu_to_le16(SMBD_V1);
- packet->max_version = cpu_to_le16(SMBD_V1);
- packet->reserved = 0;
- packet->credits_requested = cpu_to_le16(info->send_credit_target);
- packet->preferred_send_size = cpu_to_le32(info->max_send_size);
- packet->max_receive_size = cpu_to_le32(info->max_receive_size);
- packet->max_fragmented_size =
- cpu_to_le32(info->max_fragmented_recv_size);
-
- request->num_sge = 1;
- request->sge[0].addr = ib_dma_map_single(
- info->id->device, (void *)packet,
- sizeof(*packet), DMA_TO_DEVICE);
- if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) {
- rc = -EIO;
- goto dma_mapping_failed;
- }
-
- request->sge[0].length = sizeof(*packet);
- request->sge[0].lkey = info->pd->local_dma_lkey;
-
- ib_dma_sync_single_for_device(
- info->id->device, request->sge[0].addr,
- request->sge[0].length, DMA_TO_DEVICE);
-
- request->cqe.done = send_done;
-
- send_wr.next = NULL;
- send_wr.wr_cqe = &request->cqe;
- send_wr.sg_list = request->sge;
- send_wr.num_sge = request->num_sge;
- send_wr.opcode = IB_WR_SEND;
- send_wr.send_flags = IB_SEND_SIGNALED;
-
- log_rdma_send(INFO, "sge addr=0x%llx length=%u lkey=0x%x\n",
- request->sge[0].addr,
- request->sge[0].length, request->sge[0].lkey);
-
- atomic_inc(&info->send_pending);
- rc = ib_post_send(info->id->qp, &send_wr, NULL);
- if (!rc)
- return 0;
-
- /* if we reach here, post send failed */
- log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc);
- atomic_dec(&info->send_pending);
- ib_dma_unmap_single(info->id->device, request->sge[0].addr,
- request->sge[0].length, DMA_TO_DEVICE);
-
- smbd_disconnect_rdma_connection(info);
-
-dma_mapping_failed:
- mempool_free(request, info->request_mempool);
- return rc;
-}
-
-/*
- * Extend the credits to remote peer
- * This implements [MS-SMBD] 3.1.5.9
- * The idea is that we should extend credits to remote peer as quickly as
- * it's allowed, to maintain data flow. We allocate as much receive
- * buffer as possible, and extend the receive credits to remote peer
- * return value: the new credtis being granted.
- */
-static int manage_credits_prior_sending(struct smbd_connection *info)
-{
- int new_credits;
-
- spin_lock(&info->lock_new_credits_offered);
- new_credits = info->new_credits_offered;
- info->new_credits_offered = 0;
- spin_unlock(&info->lock_new_credits_offered);
-
- return new_credits;
-}
-
-/*
- * Check if we need to send a KEEP_ALIVE message
- * The idle connection timer triggers a KEEP_ALIVE message when expires
- * SMB_DIRECT_RESPONSE_REQUESTED is set in the message flag to have peer send
- * back a response.
- * return value:
- * 1 if SMB_DIRECT_RESPONSE_REQUESTED needs to be set
- * 0: otherwise
- */
-static int manage_keep_alive_before_sending(struct smbd_connection *info)
-{
- if (info->keep_alive_requested == KEEP_ALIVE_PENDING) {
- info->keep_alive_requested = KEEP_ALIVE_SENT;
- return 1;
- }
- return 0;
-}
-
-/* Post the send request */
-static int smbd_post_send(struct smbd_connection *info,
- struct smbd_request *request)
-{
- struct ib_send_wr send_wr;
- int rc, i;
-
- for (i = 0; i < request->num_sge; i++) {
- log_rdma_send(INFO,
- "rdma_request sge[%d] addr=0x%llx length=%u\n",
- i, request->sge[i].addr, request->sge[i].length);
- ib_dma_sync_single_for_device(
- info->id->device,
- request->sge[i].addr,
- request->sge[i].length,
- DMA_TO_DEVICE);
- }
-
- request->cqe.done = send_done;
-
- send_wr.next = NULL;
- send_wr.wr_cqe = &request->cqe;
- send_wr.sg_list = request->sge;
- send_wr.num_sge = request->num_sge;
- send_wr.opcode = IB_WR_SEND;
- send_wr.send_flags = IB_SEND_SIGNALED;
-
- rc = ib_post_send(info->id->qp, &send_wr, NULL);
- if (rc) {
- log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc);
- smbd_disconnect_rdma_connection(info);
- rc = -EAGAIN;
- } else
- /* Reset timer for idle connection after packet is sent */
- mod_delayed_work(info->workqueue, &info->idle_timer_work,
- info->keep_alive_interval*HZ);
-
- return rc;
-}
-
-static int smbd_post_send_iter(struct smbd_connection *info,
- struct iov_iter *iter,
- int *_remaining_data_length)
-{
- int i, rc;
- int header_length;
- int data_length;
- struct smbd_request *request;
- struct smbd_data_transfer *packet;
- int new_credits = 0;
-
-wait_credit:
- /* Wait for send credits. A SMBD packet needs one credit */
- rc = wait_event_interruptible(info->wait_send_queue,
- atomic_read(&info->send_credits) > 0 ||
- info->transport_status != SMBD_CONNECTED);
- if (rc)
- goto err_wait_credit;
-
- if (info->transport_status != SMBD_CONNECTED) {
- log_outgoing(ERR, "disconnected not sending on wait_credit\n");
- rc = -EAGAIN;
- goto err_wait_credit;
- }
- if (unlikely(atomic_dec_return(&info->send_credits) < 0)) {
- atomic_inc(&info->send_credits);
- goto wait_credit;
- }
-
-wait_send_queue:
- wait_event(info->wait_post_send,
- atomic_read(&info->send_pending) < info->send_credit_target ||
- info->transport_status != SMBD_CONNECTED);
-
- if (info->transport_status != SMBD_CONNECTED) {
- log_outgoing(ERR, "disconnected not sending on wait_send_queue\n");
- rc = -EAGAIN;
- goto err_wait_send_queue;
- }
-
- if (unlikely(atomic_inc_return(&info->send_pending) >
- info->send_credit_target)) {
- atomic_dec(&info->send_pending);
- goto wait_send_queue;
- }
-
- request = mempool_alloc(info->request_mempool, GFP_KERNEL);
- if (!request) {
- rc = -ENOMEM;
- goto err_alloc;
- }
-
- request->info = info;
- memset(request->sge, 0, sizeof(request->sge));
-
- /* Fill in the data payload to find out how much data we can add */
- if (iter) {
- struct smb_extract_to_rdma extract = {
- .nr_sge = 1,
- .max_sge = SMBDIRECT_MAX_SEND_SGE,
- .sge = request->sge,
- .device = info->id->device,
- .local_dma_lkey = info->pd->local_dma_lkey,
- .direction = DMA_TO_DEVICE,
- };
-
- rc = smb_extract_iter_to_rdma(iter, *_remaining_data_length,
- &extract);
- if (rc < 0)
- goto err_dma;
- data_length = rc;
- request->num_sge = extract.nr_sge;
- *_remaining_data_length -= data_length;
- } else {
- data_length = 0;
- request->num_sge = 1;
- }
-
- /* Fill in the packet header */
- packet = smbd_request_payload(request);
- packet->credits_requested = cpu_to_le16(info->send_credit_target);
-
- new_credits = manage_credits_prior_sending(info);
- atomic_add(new_credits, &info->receive_credits);
- packet->credits_granted = cpu_to_le16(new_credits);
-
- info->send_immediate = false;
-
- packet->flags = 0;
- if (manage_keep_alive_before_sending(info))
- packet->flags |= cpu_to_le16(SMB_DIRECT_RESPONSE_REQUESTED);
-
- packet->reserved = 0;
- if (!data_length)
- packet->data_offset = 0;
- else
- packet->data_offset = cpu_to_le32(24);
- packet->data_length = cpu_to_le32(data_length);
- packet->remaining_data_length = cpu_to_le32(*_remaining_data_length);
- packet->padding = 0;
-
- log_outgoing(INFO, "credits_requested=%d credits_granted=%d data_offset=%d data_length=%d remaining_data_length=%d\n",
- le16_to_cpu(packet->credits_requested),
- le16_to_cpu(packet->credits_granted),
- le32_to_cpu(packet->data_offset),
- le32_to_cpu(packet->data_length),
- le32_to_cpu(packet->remaining_data_length));
-
- /* Map the packet to DMA */
- header_length = sizeof(struct smbd_data_transfer);
- /* If this is a packet without payload, don't send padding */
- if (!data_length)
- header_length = offsetof(struct smbd_data_transfer, padding);
-
- request->sge[0].addr = ib_dma_map_single(info->id->device,
- (void *)packet,
- header_length,
- DMA_TO_DEVICE);
- if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) {
- rc = -EIO;
- request->sge[0].addr = 0;
- goto err_dma;
- }
-
- request->sge[0].length = header_length;
- request->sge[0].lkey = info->pd->local_dma_lkey;
-
- rc = smbd_post_send(info, request);
- if (!rc)
- return 0;
-
-err_dma:
- for (i = 0; i < request->num_sge; i++)
- if (request->sge[i].addr)
- ib_dma_unmap_single(info->id->device,
- request->sge[i].addr,
- request->sge[i].length,
- DMA_TO_DEVICE);
- mempool_free(request, info->request_mempool);
-
- /* roll back receive credits and credits to be offered */
- spin_lock(&info->lock_new_credits_offered);
- info->new_credits_offered += new_credits;
- spin_unlock(&info->lock_new_credits_offered);
- atomic_sub(new_credits, &info->receive_credits);
-
-err_alloc:
- if (atomic_dec_and_test(&info->send_pending))
- wake_up(&info->wait_send_pending);
-
-err_wait_send_queue:
- /* roll back send credits and pending */
- atomic_inc(&info->send_credits);
-
-err_wait_credit:
- return rc;
-}
-
-/*
- * Send an empty message
- * Empty message is used to extend credits to peer to for keep live
- * while there is no upper layer payload to send at the time
- */
-static int smbd_post_send_empty(struct smbd_connection *info)
-{
- int remaining_data_length = 0;
-
- info->count_send_empty++;
- return smbd_post_send_iter(info, NULL, &remaining_data_length);
-}
-
-/*
- * Post a receive request to the transport
- * The remote peer can only send data when a receive request is posted
- * The interaction is controlled by send/receive credit system
- */
-static int smbd_post_recv(
- struct smbd_connection *info, struct smbd_response *response)
-{
- struct ib_recv_wr recv_wr;
- int rc = -EIO;
-
- response->sge.addr = ib_dma_map_single(
- info->id->device, response->packet,
- info->max_receive_size, DMA_FROM_DEVICE);
- if (ib_dma_mapping_error(info->id->device, response->sge.addr))
- return rc;
-
- response->sge.length = info->max_receive_size;
- response->sge.lkey = info->pd->local_dma_lkey;
-
- response->cqe.done = recv_done;
-
- recv_wr.wr_cqe = &response->cqe;
- recv_wr.next = NULL;
- recv_wr.sg_list = &response->sge;
- recv_wr.num_sge = 1;
-
- rc = ib_post_recv(info->id->qp, &recv_wr, NULL);
- if (rc) {
- ib_dma_unmap_single(info->id->device, response->sge.addr,
- response->sge.length, DMA_FROM_DEVICE);
- smbd_disconnect_rdma_connection(info);
- log_rdma_recv(ERR, "ib_post_recv failed rc=%d\n", rc);
- }
-
- return rc;
-}
-
-/* Perform SMBD negotiate according to [MS-SMBD] 3.1.5.2 */
-static int smbd_negotiate(struct smbd_connection *info)
-{
- int rc;
- struct smbd_response *response = get_receive_buffer(info);
-
- response->type = SMBD_NEGOTIATE_RESP;
- rc = smbd_post_recv(info, response);
- log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=0x%llx iov.length=%u iov.lkey=0x%x\n",
- rc, response->sge.addr,
- response->sge.length, response->sge.lkey);
- if (rc)
- return rc;
-
- init_completion(&info->negotiate_completion);
- info->negotiate_done = false;
- rc = smbd_post_send_negotiate_req(info);
- if (rc)
- return rc;
-
- rc = wait_for_completion_interruptible_timeout(
- &info->negotiate_completion, SMBD_NEGOTIATE_TIMEOUT * HZ);
- log_rdma_event(INFO, "wait_for_completion_timeout rc=%d\n", rc);
-
- if (info->negotiate_done)
- return 0;
-
- if (rc == 0)
- rc = -ETIMEDOUT;
- else if (rc == -ERESTARTSYS)
- rc = -EINTR;
- else
- rc = -ENOTCONN;
-
- return rc;
-}
-
-static void put_empty_packet(
- struct smbd_connection *info, struct smbd_response *response)
-{
- spin_lock(&info->empty_packet_queue_lock);
- list_add_tail(&response->list, &info->empty_packet_queue);
- info->count_empty_packet_queue++;
- spin_unlock(&info->empty_packet_queue_lock);
-
- queue_work(info->workqueue, &info->post_send_credits_work);
-}
-
-/*
- * Implement Connection.FragmentReassemblyBuffer defined in [MS-SMBD] 3.1.1.1
- * This is a queue for reassembling upper layer payload and present to upper
- * layer. All the inncoming payload go to the reassembly queue, regardless of
- * if reassembly is required. The uuper layer code reads from the queue for all
- * incoming payloads.
- * Put a received packet to the reassembly queue
- * response: the packet received
- * data_length: the size of payload in this packet
- */
-static void enqueue_reassembly(
- struct smbd_connection *info,
- struct smbd_response *response,
- int data_length)
-{
- spin_lock(&info->reassembly_queue_lock);
- list_add_tail(&response->list, &info->reassembly_queue);
- info->reassembly_queue_length++;
/*
- * Make sure reassembly_data_length is updated after list and
- * reassembly_queue_length are updated. On the dequeue side
- * reassembly_data_length is checked without a lock to determine
- * if reassembly_queue_length and list is up to date
+ * smbdirect_connection_send_single_iter() respects the
+ * negotiated max_send_size, so we need to
+ * loop until the full iter is posted
*/
- virt_wmb();
- info->reassembly_data_length += data_length;
- spin_unlock(&info->reassembly_queue_lock);
- info->count_reassembly_queue++;
- info->count_enqueue_reassembly_queue++;
-}
-
-/*
- * Get the first entry at the front of reassembly queue
- * Caller is responsible for locking
- * return value: the first entry if any, NULL if queue is empty
- */
-static struct smbd_response *_get_first_reassembly(struct smbd_connection *info)
-{
- struct smbd_response *ret = NULL;
-
- if (!list_empty(&info->reassembly_queue)) {
- ret = list_first_entry(
- &info->reassembly_queue,
- struct smbd_response, list);
- }
- return ret;
-}
-
-static struct smbd_response *get_empty_queue_buffer(
- struct smbd_connection *info)
-{
- struct smbd_response *ret = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&info->empty_packet_queue_lock, flags);
- if (!list_empty(&info->empty_packet_queue)) {
- ret = list_first_entry(
- &info->empty_packet_queue,
- struct smbd_response, list);
- list_del(&ret->list);
- info->count_empty_packet_queue--;
- }
- spin_unlock_irqrestore(&info->empty_packet_queue_lock, flags);
-
- return ret;
-}
-
-/*
- * Get a receive buffer
- * For each remote send, we need to post a receive. The receive buffers are
- * pre-allocated in advance.
- * return value: the receive buffer, NULL if none is available
- */
-static struct smbd_response *get_receive_buffer(struct smbd_connection *info)
-{
- struct smbd_response *ret = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&info->receive_queue_lock, flags);
- if (!list_empty(&info->receive_queue)) {
- ret = list_first_entry(
- &info->receive_queue,
- struct smbd_response, list);
- list_del(&ret->list);
- info->count_receive_queue--;
- info->count_get_receive_buffer++;
- }
- spin_unlock_irqrestore(&info->receive_queue_lock, flags);
-
- return ret;
-}
-
-/*
- * Return a receive buffer
- * Upon returning of a receive buffer, we can post new receive and extend
- * more receive credits to remote peer. This is done immediately after a
- * receive buffer is returned.
- */
-static void put_receive_buffer(
- struct smbd_connection *info, struct smbd_response *response)
-{
- unsigned long flags;
-
- ib_dma_unmap_single(info->id->device, response->sge.addr,
- response->sge.length, DMA_FROM_DEVICE);
-
- spin_lock_irqsave(&info->receive_queue_lock, flags);
- list_add_tail(&response->list, &info->receive_queue);
- info->count_receive_queue++;
- info->count_put_receive_buffer++;
- spin_unlock_irqrestore(&info->receive_queue_lock, flags);
-
- queue_work(info->workqueue, &info->post_send_credits_work);
-}
-
-/* Preallocate all receive buffer on transport establishment */
-static int allocate_receive_buffers(struct smbd_connection *info, int num_buf)
-{
- int i;
- struct smbd_response *response;
-
- INIT_LIST_HEAD(&info->reassembly_queue);
- spin_lock_init(&info->reassembly_queue_lock);
- info->reassembly_data_length = 0;
- info->reassembly_queue_length = 0;
-
- INIT_LIST_HEAD(&info->receive_queue);
- spin_lock_init(&info->receive_queue_lock);
- info->count_receive_queue = 0;
- INIT_LIST_HEAD(&info->empty_packet_queue);
- spin_lock_init(&info->empty_packet_queue_lock);
- info->count_empty_packet_queue = 0;
+ while (iov_iter_count(iter) > 0) {
+ int rc;
- init_waitqueue_head(&info->wait_receive_queues);
-
- for (i = 0; i < num_buf; i++) {
- response = mempool_alloc(info->response_mempool, GFP_KERNEL);
- if (!response)
- goto allocate_failed;
-
- response->info = info;
- list_add_tail(&response->list, &info->receive_queue);
- info->count_receive_queue++;
- }
-
- return 0;
-
-allocate_failed:
- while (!list_empty(&info->receive_queue)) {
- response = list_first_entry(
- &info->receive_queue,
- struct smbd_response, list);
- list_del(&response->list);
- info->count_receive_queue--;
-
- mempool_free(response, info->response_mempool);
- }
- return -ENOMEM;
-}
-
-static void destroy_receive_buffers(struct smbd_connection *info)
-{
- struct smbd_response *response;
-
- while ((response = get_receive_buffer(info)))
- mempool_free(response, info->response_mempool);
-
- while ((response = get_empty_queue_buffer(info)))
- mempool_free(response, info->response_mempool);
-}
-
-/* Implement idle connection timer [MS-SMBD] 3.1.6.2 */
-static void idle_connection_timer(struct work_struct *work)
-{
- struct smbd_connection *info = container_of(
- work, struct smbd_connection,
- idle_timer_work.work);
-
- if (info->keep_alive_requested != KEEP_ALIVE_NONE) {
- log_keep_alive(ERR,
- "error status info->keep_alive_requested=%d\n",
- info->keep_alive_requested);
- smbd_disconnect_rdma_connection(info);
- return;
+ rc = smbdirect_connection_send_single_iter(sc,
+ batch,
+ iter,
+ 0, /* flags */
+ remaining_data_length);
+ if (rc < 0)
+ return rc;
+ remaining_data_length -= rc;
+ bytes += rc;
}
- log_keep_alive(INFO, "about to send an empty idle message\n");
- smbd_post_send_empty(info);
-
- /* Setup the next idle timeout work */
- queue_delayed_work(info->workqueue, &info->idle_timer_work,
- info->keep_alive_interval*HZ);
+ return bytes;
}
/*
@@ -1289,88 +203,14 @@ static void idle_connection_timer(struct work_struct *work)
void smbd_destroy(struct TCP_Server_Info *server)
{
struct smbd_connection *info = server->smbd_conn;
- struct smbd_response *response;
- unsigned long flags;
if (!info) {
log_rdma_event(INFO, "rdma session already destroyed\n");
return;
}
- log_rdma_event(INFO, "destroying rdma session\n");
- if (info->transport_status != SMBD_DISCONNECTED) {
- rdma_disconnect(server->smbd_conn->id);
- log_rdma_event(INFO, "wait for transport being disconnected\n");
- wait_event_interruptible(
- info->disconn_wait,
- info->transport_status == SMBD_DISCONNECTED);
- }
-
- log_rdma_event(INFO, "destroying qp\n");
- ib_drain_qp(info->id->qp);
- rdma_destroy_qp(info->id);
-
- log_rdma_event(INFO, "cancelling idle timer\n");
- cancel_delayed_work_sync(&info->idle_timer_work);
-
- log_rdma_event(INFO, "wait for all send posted to IB to finish\n");
- wait_event(info->wait_send_pending,
- atomic_read(&info->send_pending) == 0);
-
- /* It's not possible for upper layer to get to reassembly */
- log_rdma_event(INFO, "drain the reassembly queue\n");
- do {
- spin_lock_irqsave(&info->reassembly_queue_lock, flags);
- response = _get_first_reassembly(info);
- if (response) {
- list_del(&response->list);
- spin_unlock_irqrestore(
- &info->reassembly_queue_lock, flags);
- put_receive_buffer(info, response);
- } else
- spin_unlock_irqrestore(
- &info->reassembly_queue_lock, flags);
- } while (response);
- info->reassembly_data_length = 0;
-
- log_rdma_event(INFO, "free receive buffers\n");
- wait_event(info->wait_receive_queues,
- info->count_receive_queue + info->count_empty_packet_queue
- == info->receive_credit_max);
- destroy_receive_buffers(info);
-
- /*
- * For performance reasons, memory registration and deregistration
- * are not locked by srv_mutex. It is possible some processes are
- * blocked on transport srv_mutex while holding memory registration.
- * Release the transport srv_mutex to allow them to hit the failure
- * path when sending data, and then release memory registrations.
- */
- log_rdma_event(INFO, "freeing mr list\n");
- wake_up_interruptible_all(&info->wait_mr);
- while (atomic_read(&info->mr_used_count)) {
- cifs_server_unlock(server);
- msleep(1000);
- cifs_server_lock(server);
- }
- destroy_mr_list(info);
-
- ib_free_cq(info->send_cq);
- ib_free_cq(info->recv_cq);
- ib_dealloc_pd(info->pd);
- rdma_destroy_id(info->id);
-
- /* free mempools */
- mempool_destroy(info->request_mempool);
- kmem_cache_destroy(info->request_cache);
-
- mempool_destroy(info->response_mempool);
- kmem_cache_destroy(info->response_cache);
-
- info->transport_status = SMBD_DESTROYED;
+ smbdirect_socket_release(info->socket);
- destroy_workqueue(info->workqueue);
- log_rdma_event(INFO, "rdma session destroyed\n");
kfree(info);
server->smbd_conn = NULL;
}
@@ -1392,10 +232,8 @@ int smbd_reconnect(struct TCP_Server_Info *server)
* This is possible if transport is disconnected and we haven't received
* notification from RDMA, but upper layer has detected timeout
*/
- if (server->smbd_conn->transport_status == SMBD_CONNECTED) {
- log_rdma_event(INFO, "disconnecting transport\n");
- smbd_destroy(server);
- }
+ log_rdma_event(INFO, "disconnecting transport\n");
+ smbd_destroy(server);
create_conn:
log_rdma_event(INFO, "creating rdma session\n");
@@ -1411,300 +249,114 @@ create_conn:
return -ENOENT;
}
-static void destroy_caches_and_workqueue(struct smbd_connection *info)
-{
- destroy_receive_buffers(info);
- destroy_workqueue(info->workqueue);
- mempool_destroy(info->response_mempool);
- kmem_cache_destroy(info->response_cache);
- mempool_destroy(info->request_mempool);
- kmem_cache_destroy(info->request_cache);
-}
-
-#define MAX_NAME_LEN 80
-static int allocate_caches_and_workqueue(struct smbd_connection *info)
-{
- char name[MAX_NAME_LEN];
- int rc;
-
- scnprintf(name, MAX_NAME_LEN, "smbd_request_%p", info);
- info->request_cache =
- kmem_cache_create(
- name,
- sizeof(struct smbd_request) +
- sizeof(struct smbd_data_transfer),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!info->request_cache)
- return -ENOMEM;
-
- info->request_mempool =
- mempool_create(info->send_credit_target, mempool_alloc_slab,
- mempool_free_slab, info->request_cache);
- if (!info->request_mempool)
- goto out1;
-
- scnprintf(name, MAX_NAME_LEN, "smbd_response_%p", info);
- info->response_cache =
- kmem_cache_create(
- name,
- sizeof(struct smbd_response) +
- info->max_receive_size,
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!info->response_cache)
- goto out2;
-
- info->response_mempool =
- mempool_create(info->receive_credit_max, mempool_alloc_slab,
- mempool_free_slab, info->response_cache);
- if (!info->response_mempool)
- goto out3;
-
- scnprintf(name, MAX_NAME_LEN, "smbd_%p", info);
- info->workqueue = create_workqueue(name);
- if (!info->workqueue)
- goto out4;
-
- rc = allocate_receive_buffers(info, info->receive_credit_max);
- if (rc) {
- log_rdma_event(ERR, "failed to allocate receive buffers\n");
- goto out5;
- }
-
- return 0;
-
-out5:
- destroy_workqueue(info->workqueue);
-out4:
- mempool_destroy(info->response_mempool);
-out3:
- kmem_cache_destroy(info->response_cache);
-out2:
- mempool_destroy(info->request_mempool);
-out1:
- kmem_cache_destroy(info->request_cache);
- return -ENOMEM;
-}
-
/* Create a SMBD connection, called by upper layer */
static struct smbd_connection *_smbd_get_connection(
struct TCP_Server_Info *server, struct sockaddr *dstaddr, int port)
{
- int rc;
+ struct net *net = cifs_net_ns(server);
struct smbd_connection *info;
- struct rdma_conn_param conn_param;
- struct ib_qp_init_attr qp_attr;
- struct sockaddr_in *addr_in = (struct sockaddr_in *) dstaddr;
- struct ib_port_immutable port_immutable;
- u32 ird_ord_hdr[2];
-
- info = kzalloc(sizeof(struct smbd_connection), GFP_KERNEL);
- if (!info)
- return NULL;
-
- info->transport_status = SMBD_CONNECTING;
- rc = smbd_ia_open(info, dstaddr, port);
- if (rc) {
- log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc);
- goto create_id_failed;
- }
-
- if (smbd_send_credit_target > info->id->device->attrs.max_cqe ||
- smbd_send_credit_target > info->id->device->attrs.max_qp_wr) {
- log_rdma_event(ERR, "consider lowering send_credit_target = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n",
- smbd_send_credit_target,
- info->id->device->attrs.max_cqe,
- info->id->device->attrs.max_qp_wr);
- goto config_failed;
- }
-
- if (smbd_receive_credit_max > info->id->device->attrs.max_cqe ||
- smbd_receive_credit_max > info->id->device->attrs.max_qp_wr) {
- log_rdma_event(ERR, "consider lowering receive_credit_max = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n",
- smbd_receive_credit_max,
- info->id->device->attrs.max_cqe,
- info->id->device->attrs.max_qp_wr);
- goto config_failed;
- }
-
- info->receive_credit_max = smbd_receive_credit_max;
- info->send_credit_target = smbd_send_credit_target;
- info->max_send_size = smbd_max_send_size;
- info->max_fragmented_recv_size = smbd_max_fragmented_recv_size;
- info->max_receive_size = smbd_max_receive_size;
- info->keep_alive_interval = smbd_keep_alive_interval;
-
- if (info->id->device->attrs.max_send_sge < SMBDIRECT_MAX_SEND_SGE ||
- info->id->device->attrs.max_recv_sge < SMBDIRECT_MAX_RECV_SGE) {
- log_rdma_event(ERR,
- "device %.*s max_send_sge/max_recv_sge = %d/%d too small\n",
- IB_DEVICE_NAME_MAX,
- info->id->device->name,
- info->id->device->attrs.max_send_sge,
- info->id->device->attrs.max_recv_sge);
- goto config_failed;
- }
-
- info->send_cq = NULL;
- info->recv_cq = NULL;
- info->send_cq =
- ib_alloc_cq_any(info->id->device, info,
- info->send_credit_target, IB_POLL_SOFTIRQ);
- if (IS_ERR(info->send_cq)) {
- info->send_cq = NULL;
- goto alloc_cq_failed;
- }
-
- info->recv_cq =
- ib_alloc_cq_any(info->id->device, info,
- info->receive_credit_max, IB_POLL_SOFTIRQ);
- if (IS_ERR(info->recv_cq)) {
- info->recv_cq = NULL;
- goto alloc_cq_failed;
- }
-
- memset(&qp_attr, 0, sizeof(qp_attr));
- qp_attr.event_handler = smbd_qp_async_error_upcall;
- qp_attr.qp_context = info;
- qp_attr.cap.max_send_wr = info->send_credit_target;
- qp_attr.cap.max_recv_wr = info->receive_credit_max;
- qp_attr.cap.max_send_sge = SMBDIRECT_MAX_SEND_SGE;
- qp_attr.cap.max_recv_sge = SMBDIRECT_MAX_RECV_SGE;
- qp_attr.cap.max_inline_data = 0;
- qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
- qp_attr.qp_type = IB_QPT_RC;
- qp_attr.send_cq = info->send_cq;
- qp_attr.recv_cq = info->recv_cq;
- qp_attr.port_num = ~0;
-
- rc = rdma_create_qp(info->id, info->pd, &qp_attr);
- if (rc) {
- log_rdma_event(ERR, "rdma_create_qp failed %i\n", rc);
- goto create_qp_failed;
- }
-
- memset(&conn_param, 0, sizeof(conn_param));
- conn_param.initiator_depth = 0;
-
- conn_param.responder_resources =
- min(info->id->device->attrs.max_qp_rd_atom,
- SMBD_CM_RESPONDER_RESOURCES);
- info->responder_resources = conn_param.responder_resources;
- log_rdma_mr(INFO, "responder_resources=%d\n",
- info->responder_resources);
-
- /* Need to send IRD/ORD in private data for iWARP */
- info->id->device->ops.get_port_immutable(
- info->id->device, info->id->port_num, &port_immutable);
- if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) {
- ird_ord_hdr[0] = info->responder_resources;
- ird_ord_hdr[1] = 1;
- conn_param.private_data = ird_ord_hdr;
- conn_param.private_data_len = sizeof(ird_ord_hdr);
- } else {
- conn_param.private_data = NULL;
- conn_param.private_data_len = 0;
- }
-
- conn_param.retry_count = SMBD_CM_RETRY;
- conn_param.rnr_retry_count = SMBD_CM_RNR_RETRY;
- conn_param.flow_control = 0;
-
- log_rdma_event(INFO, "connecting to IP %pI4 port %d\n",
- &addr_in->sin_addr, port);
+ struct smbdirect_socket *sc;
+ struct smbdirect_socket_parameters init_params = {};
+ struct smbdirect_socket_parameters *sp;
+ __be16 *sport;
+ u64 port_flags = 0;
+ int ret;
- init_waitqueue_head(&info->conn_wait);
- init_waitqueue_head(&info->disconn_wait);
- init_waitqueue_head(&info->wait_reassembly_queue);
- rc = rdma_connect(info->id, &conn_param);
- if (rc) {
- log_rdma_event(ERR, "rdma_connect() failed with %i\n", rc);
- goto rdma_connect_failed;
+ switch (port) {
+ case SMBD_PORT:
+ /*
+ * only allow iWarp devices
+ * for port 5445.
+ */
+ port_flags |= SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW;
+ break;
+ case SMB_PORT:
+ /*
+ * only allow InfiniBand, RoCEv1 or RoCEv2
+ * devices for port 445.
+ *
+ * (Basically don't allow iWarp devices)
+ */
+ port_flags |= SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB;
+ break;
}
- wait_event_interruptible(
- info->conn_wait, info->transport_status != SMBD_CONNECTING);
+ /*
+ * Create the initial parameters
+ */
+ sp = &init_params;
+ sp->flags = port_flags;
+ sp->resolve_addr_timeout_msec = RDMA_RESOLVE_TIMEOUT;
+ sp->resolve_route_timeout_msec = RDMA_RESOLVE_TIMEOUT;
+ sp->rdma_connect_timeout_msec = RDMA_RESOLVE_TIMEOUT;
+ sp->negotiate_timeout_msec = SMBD_NEGOTIATE_TIMEOUT * 1000;
+ sp->initiator_depth = 1;
+ sp->responder_resources = SMBD_CM_RESPONDER_RESOURCES;
+ sp->recv_credit_max = smbd_receive_credit_max;
+ sp->send_credit_target = smbd_send_credit_target;
+ sp->max_send_size = smbd_max_send_size;
+ sp->max_fragmented_recv_size = smbd_max_fragmented_recv_size;
+ sp->max_recv_size = smbd_max_receive_size;
+ sp->max_frmr_depth = smbd_max_frmr_depth;
+ sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000;
+ sp->keepalive_timeout_msec = KEEPALIVE_RECV_TIMEOUT * 1000;
+
+ info = kzalloc_obj(*info);
+ if (!info)
+ return NULL;
+ ret = smbdirect_socket_create_kern(net, &sc);
+ if (ret)
+ goto socket_init_failed;
+ smbdirect_socket_set_logging(sc, NULL, smbd_logging_needed, smbd_logging_vaprintf);
+ ret = smbdirect_socket_set_initial_parameters(sc, sp);
+ if (ret)
+ goto set_params_failed;
+ ret = smbdirect_socket_set_kernel_settings(sc, IB_POLL_SOFTIRQ, GFP_KERNEL);
+ if (ret)
+ goto set_settings_failed;
- if (info->transport_status != SMBD_CONNECTED) {
- log_rdma_event(ERR, "rdma_connect failed port=%d\n", port);
- goto rdma_connect_failed;
- }
+ if (dstaddr->sa_family == AF_INET6)
+ sport = &((struct sockaddr_in6 *)dstaddr)->sin6_port;
+ else
+ sport = &((struct sockaddr_in *)dstaddr)->sin_port;
- log_rdma_event(INFO, "rdma_connect connected\n");
+ *sport = htons(port);
- rc = allocate_caches_and_workqueue(info);
- if (rc) {
- log_rdma_event(ERR, "cache allocation failed\n");
- goto allocate_cache_failed;
+ ret = smbdirect_connect_sync(sc, dstaddr);
+ if (ret) {
+ log_rdma_event(ERR, "connect to %pISpsfc failed: %1pe\n",
+ dstaddr, ERR_PTR(ret));
+ goto connect_failed;
}
- init_waitqueue_head(&info->wait_send_queue);
- INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer);
- queue_delayed_work(info->workqueue, &info->idle_timer_work,
- info->keep_alive_interval*HZ);
-
- init_waitqueue_head(&info->wait_send_pending);
- atomic_set(&info->send_pending, 0);
-
- init_waitqueue_head(&info->wait_post_send);
+ info->socket = sc;
+ return info;
- INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work);
- INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits);
- info->new_credits_offered = 0;
- spin_lock_init(&info->lock_new_credits_offered);
+connect_failed:
+set_settings_failed:
+set_params_failed:
+ smbdirect_socket_release(sc);
+socket_init_failed:
+ kfree(info);
+ return NULL;
+}
- rc = smbd_negotiate(info);
- if (rc) {
- log_rdma_event(ERR, "smbd_negotiate rc=%d\n", rc);
- goto negotiation_failed;
- }
+const struct smbdirect_socket_parameters *smbd_get_parameters(struct smbd_connection *conn)
+{
+ if (unlikely(!conn->socket)) {
+ static const struct smbdirect_socket_parameters zero_params;
- rc = allocate_mr_list(info);
- if (rc) {
- log_rdma_mr(ERR, "memory registration allocation failed\n");
- goto allocate_mr_failed;
+ return &zero_params;
}
- return info;
-
-allocate_mr_failed:
- /* At this point, need to a full transport shutdown */
- server->smbd_conn = info;
- smbd_destroy(server);
- return NULL;
-
-negotiation_failed:
- cancel_delayed_work_sync(&info->idle_timer_work);
- destroy_caches_and_workqueue(info);
- info->transport_status = SMBD_NEGOTIATE_FAILED;
- init_waitqueue_head(&info->conn_wait);
- rdma_disconnect(info->id);
- wait_event(info->conn_wait,
- info->transport_status == SMBD_DISCONNECTED);
-
-allocate_cache_failed:
-rdma_connect_failed:
- rdma_destroy_qp(info->id);
-
-create_qp_failed:
-alloc_cq_failed:
- if (info->send_cq)
- ib_free_cq(info->send_cq);
- if (info->recv_cq)
- ib_free_cq(info->recv_cq);
-
-config_failed:
- ib_dealloc_pd(info->pd);
- rdma_destroy_id(info->id);
-
-create_id_failed:
- kfree(info);
- return NULL;
+ return smbdirect_socket_get_current_parameters(conn->socket);
}
struct smbd_connection *smbd_get_connection(
struct TCP_Server_Info *server, struct sockaddr *dstaddr)
{
struct smbd_connection *ret;
+ const struct smbdirect_socket_parameters *sp;
int port = SMBD_PORT;
try_again:
@@ -1715,233 +367,41 @@ try_again:
port = SMB_PORT;
goto try_again;
}
+ if (!ret)
+ return NULL;
+
+ sp = smbd_get_parameters(ret);
+
+ server->rdma_readwrite_threshold =
+ rdma_readwrite_threshold > sp->max_fragmented_send_size ?
+ sp->max_fragmented_send_size :
+ rdma_readwrite_threshold;
+
return ret;
}
/*
- * Receive data from receive reassembly queue
+ * Receive data from the transport's receive reassembly queue
* All the incoming data packets are placed in reassembly queue
- * buf: the buffer to read data into
+ * iter: the buffer to read data into
* size: the length of data to read
* return value: actual data read
- * Note: this implementation copies the data from reassebmly queue to receive
+ *
+ * Note: this implementation copies the data from reassembly queue to receive
* buffers used by upper layer. This is not the optimal code path. A better way
* to do it is to not have upper layer allocate its receive buffers but rather
* borrow the buffer from reassembly queue, and return it after data is
* consumed. But this will require more changes to upper layer code, and also
* need to consider packet boundaries while they still being reassembled.
*/
-static int smbd_recv_buf(struct smbd_connection *info, char *buf,
- unsigned int size)
-{
- struct smbd_response *response;
- struct smbd_data_transfer *data_transfer;
- int to_copy, to_read, data_read, offset;
- u32 data_length, remaining_data_length, data_offset;
- int rc;
-
-again:
- /*
- * No need to hold the reassembly queue lock all the time as we are
- * the only one reading from the front of the queue. The transport
- * may add more entries to the back of the queue at the same time
- */
- log_read(INFO, "size=%d info->reassembly_data_length=%d\n", size,
- info->reassembly_data_length);
- if (info->reassembly_data_length >= size) {
- int queue_length;
- int queue_removed = 0;
-
- /*
- * Need to make sure reassembly_data_length is read before
- * reading reassembly_queue_length and calling
- * _get_first_reassembly. This call is lock free
- * as we never read at the end of the queue which are being
- * updated in SOFTIRQ as more data is received
- */
- virt_rmb();
- queue_length = info->reassembly_queue_length;
- data_read = 0;
- to_read = size;
- offset = info->first_entry_offset;
- while (data_read < size) {
- response = _get_first_reassembly(info);
- data_transfer = smbd_response_payload(response);
- data_length = le32_to_cpu(data_transfer->data_length);
- remaining_data_length =
- le32_to_cpu(
- data_transfer->remaining_data_length);
- data_offset = le32_to_cpu(data_transfer->data_offset);
-
- /*
- * The upper layer expects RFC1002 length at the
- * beginning of the payload. Return it to indicate
- * the total length of the packet. This minimize the
- * change to upper layer packet processing logic. This
- * will be eventually remove when an intermediate
- * transport layer is added
- */
- if (response->first_segment && size == 4) {
- unsigned int rfc1002_len =
- data_length + remaining_data_length;
- *((__be32 *)buf) = cpu_to_be32(rfc1002_len);
- data_read = 4;
- response->first_segment = false;
- log_read(INFO, "returning rfc1002 length %d\n",
- rfc1002_len);
- goto read_rfc1002_done;
- }
-
- to_copy = min_t(int, data_length - offset, to_read);
- memcpy(
- buf + data_read,
- (char *)data_transfer + data_offset + offset,
- to_copy);
-
- /* move on to the next buffer? */
- if (to_copy == data_length - offset) {
- queue_length--;
- /*
- * No need to lock if we are not at the
- * end of the queue
- */
- if (queue_length)
- list_del(&response->list);
- else {
- spin_lock_irq(
- &info->reassembly_queue_lock);
- list_del(&response->list);
- spin_unlock_irq(
- &info->reassembly_queue_lock);
- }
- queue_removed++;
- info->count_reassembly_queue--;
- info->count_dequeue_reassembly_queue++;
- put_receive_buffer(info, response);
- offset = 0;
- log_read(INFO, "put_receive_buffer offset=0\n");
- } else
- offset += to_copy;
-
- to_read -= to_copy;
- data_read += to_copy;
-
- log_read(INFO, "_get_first_reassembly memcpy %d bytes data_transfer_length-offset=%d after that to_read=%d data_read=%d offset=%d\n",
- to_copy, data_length - offset,
- to_read, data_read, offset);
- }
-
- spin_lock_irq(&info->reassembly_queue_lock);
- info->reassembly_data_length -= data_read;
- info->reassembly_queue_length -= queue_removed;
- spin_unlock_irq(&info->reassembly_queue_lock);
-
- info->first_entry_offset = offset;
- log_read(INFO, "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n",
- data_read, info->reassembly_data_length,
- info->first_entry_offset);
-read_rfc1002_done:
- return data_read;
- }
-
- log_read(INFO, "wait_event on more data\n");
- rc = wait_event_interruptible(
- info->wait_reassembly_queue,
- info->reassembly_data_length >= size ||
- info->transport_status != SMBD_CONNECTED);
- /* Don't return any data if interrupted */
- if (rc)
- return rc;
-
- if (info->transport_status != SMBD_CONNECTED) {
- log_read(ERR, "disconnected\n");
- return -ECONNABORTED;
- }
-
- goto again;
-}
-
-/*
- * Receive a page from receive reassembly queue
- * page: the page to read data into
- * to_read: the length of data to read
- * return value: actual data read
- */
-static int smbd_recv_page(struct smbd_connection *info,
- struct page *page, unsigned int page_offset,
- unsigned int to_read)
-{
- int ret;
- char *to_address;
- void *page_address;
-
- /* make sure we have the page ready for read */
- ret = wait_event_interruptible(
- info->wait_reassembly_queue,
- info->reassembly_data_length >= to_read ||
- info->transport_status != SMBD_CONNECTED);
- if (ret)
- return ret;
-
- /* now we can read from reassembly queue and not sleep */
- page_address = kmap_atomic(page);
- to_address = (char *) page_address + page_offset;
-
- log_read(INFO, "reading from page=%p address=%p to_read=%d\n",
- page, to_address, to_read);
-
- ret = smbd_recv_buf(info, to_address, to_read);
- kunmap_atomic(page_address);
-
- return ret;
-}
-
-/*
- * Receive data from transport
- * msg: a msghdr point to the buffer, can be ITER_KVEC or ITER_BVEC
- * return: total bytes read, or 0. SMB Direct will not do partial read.
- */
int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
{
- char *buf;
- struct page *page;
- unsigned int to_read, page_offset;
- int rc;
-
- if (iov_iter_rw(&msg->msg_iter) == WRITE) {
- /* It's a bug in upper layer to get there */
- cifs_dbg(VFS, "Invalid msg iter dir %u\n",
- iov_iter_rw(&msg->msg_iter));
- rc = -EINVAL;
- goto out;
- }
-
- switch (iov_iter_type(&msg->msg_iter)) {
- case ITER_KVEC:
- buf = msg->msg_iter.kvec->iov_base;
- to_read = msg->msg_iter.kvec->iov_len;
- rc = smbd_recv_buf(info, buf, to_read);
- break;
-
- case ITER_BVEC:
- page = msg->msg_iter.bvec->bv_page;
- page_offset = msg->msg_iter.bvec->bv_offset;
- to_read = msg->msg_iter.bvec->bv_len;
- rc = smbd_recv_page(info, page, page_offset, to_read);
- break;
+ struct smbdirect_socket *sc = info->socket;
- default:
- /* It's a bug in upper layer to get there */
- cifs_dbg(VFS, "Invalid msg type %d\n",
- iov_iter_type(&msg->msg_iter));
- rc = -EINVAL;
- }
+ if (!smbdirect_connection_is_connected(sc))
+ return -ENOTCONN;
-out:
- /* SMBDirect will read it all or nothing */
- if (rc > 0)
- msg->msg_iter.count = 0;
- return rc;
+ return smbdirect_connection_recvmsg(sc, msg, 0);
}
/*
@@ -1954,12 +414,17 @@ int smbd_send(struct TCP_Server_Info *server,
int num_rqst, struct smb_rqst *rqst_array)
{
struct smbd_connection *info = server->smbd_conn;
+ struct smbdirect_socket *sc = info->socket;
+ const struct smbdirect_socket_parameters *sp = smbd_get_parameters(info);
struct smb_rqst *rqst;
struct iov_iter iter;
+ struct smbdirect_send_batch_storage bstorage;
+ struct smbdirect_send_batch *batch;
unsigned int remaining_data_length, klen;
int rc, i, rqst_idx;
+ int error = 0;
- if (info->transport_status != SMBD_CONNECTED)
+ if (!smbdirect_connection_is_connected(sc))
return -EAGAIN;
/*
@@ -1971,10 +436,10 @@ int smbd_send(struct TCP_Server_Info *server,
for (i = 0; i < num_rqst; i++)
remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
- if (unlikely(remaining_data_length > info->max_fragmented_send_size)) {
+ if (unlikely(remaining_data_length > sp->max_fragmented_send_size)) {
/* assertion: payload never exceeds negotiated maximum */
log_write(ERR, "payload size %d > max size %d\n",
- remaining_data_length, info->max_fragmented_send_size);
+ remaining_data_length, sp->max_fragmented_send_size);
return -EINVAL;
}
@@ -1982,6 +447,7 @@ int smbd_send(struct TCP_Server_Info *server,
num_rqst, remaining_data_length);
rqst_idx = 0;
+ batch = smbdirect_init_send_batch_storage(&bstorage, false, 0);
do {
rqst = &rqst_array[rqst_idx];
@@ -2000,20 +466,30 @@ int smbd_send(struct TCP_Server_Info *server,
klen += rqst->rq_iov[i].iov_len;
iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, klen);
- rc = smbd_post_send_iter(info, &iter, &remaining_data_length);
- if (rc < 0)
+ rc = smbd_post_send_full_iter(sc, batch, &iter, remaining_data_length);
+ if (rc < 0) {
+ error = rc;
break;
+ }
+ remaining_data_length -= rc;
if (iov_iter_count(&rqst->rq_iter) > 0) {
/* And then the data pages if there are any */
- rc = smbd_post_send_iter(info, &rqst->rq_iter,
- &remaining_data_length);
- if (rc < 0)
+ rc = smbd_post_send_full_iter(sc, batch, &rqst->rq_iter,
+ remaining_data_length);
+ if (rc < 0) {
+ error = rc;
break;
+ }
+ remaining_data_length -= rc;
}
} while (++rqst_idx < num_rqst);
+ rc = smbdirect_connection_send_batch_flush(sc, batch, true);
+ if (unlikely(!rc && error))
+ rc = error;
+
/*
* As an optimization, we don't wait for individual I/O to finish
* before sending the next one.
@@ -2021,219 +497,15 @@ int smbd_send(struct TCP_Server_Info *server,
* that means all the I/Os have been out and we are good to return
*/
- wait_event(info->wait_send_pending,
- atomic_read(&info->send_pending) == 0);
+ error = rc;
+ rc = smbdirect_connection_send_wait_zero_pending(sc);
+ if (unlikely(rc && !error))
+ error = -EAGAIN;
- return rc;
-}
-
-static void register_mr_done(struct ib_cq *cq, struct ib_wc *wc)
-{
- struct smbd_mr *mr;
- struct ib_cqe *cqe;
-
- if (wc->status) {
- log_rdma_mr(ERR, "status=%d\n", wc->status);
- cqe = wc->wr_cqe;
- mr = container_of(cqe, struct smbd_mr, cqe);
- smbd_disconnect_rdma_connection(mr->conn);
- }
-}
+ if (unlikely(error))
+ return error;
-/*
- * The work queue function that recovers MRs
- * We need to call ib_dereg_mr() and ib_alloc_mr() before this MR can be used
- * again. Both calls are slow, so finish them in a workqueue. This will not
- * block I/O path.
- * There is one workqueue that recovers MRs, there is no need to lock as the
- * I/O requests calling smbd_register_mr will never update the links in the
- * mr_list.
- */
-static void smbd_mr_recovery_work(struct work_struct *work)
-{
- struct smbd_connection *info =
- container_of(work, struct smbd_connection, mr_recovery_work);
- struct smbd_mr *smbdirect_mr;
- int rc;
-
- list_for_each_entry(smbdirect_mr, &info->mr_list, list) {
- if (smbdirect_mr->state == MR_ERROR) {
-
- /* recover this MR entry */
- rc = ib_dereg_mr(smbdirect_mr->mr);
- if (rc) {
- log_rdma_mr(ERR,
- "ib_dereg_mr failed rc=%x\n",
- rc);
- smbd_disconnect_rdma_connection(info);
- continue;
- }
-
- smbdirect_mr->mr = ib_alloc_mr(
- info->pd, info->mr_type,
- info->max_frmr_depth);
- if (IS_ERR(smbdirect_mr->mr)) {
- log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n",
- info->mr_type,
- info->max_frmr_depth);
- smbd_disconnect_rdma_connection(info);
- continue;
- }
- } else
- /* This MR is being used, don't recover it */
- continue;
-
- smbdirect_mr->state = MR_READY;
-
- /* smbdirect_mr->state is updated by this function
- * and is read and updated by I/O issuing CPUs trying
- * to get a MR, the call to atomic_inc_return
- * implicates a memory barrier and guarantees this
- * value is updated before waking up any calls to
- * get_mr() from the I/O issuing CPUs
- */
- if (atomic_inc_return(&info->mr_ready_count) == 1)
- wake_up_interruptible(&info->wait_mr);
- }
-}
-
-static void destroy_mr_list(struct smbd_connection *info)
-{
- struct smbd_mr *mr, *tmp;
-
- cancel_work_sync(&info->mr_recovery_work);
- list_for_each_entry_safe(mr, tmp, &info->mr_list, list) {
- if (mr->state == MR_INVALIDATED)
- ib_dma_unmap_sg(info->id->device, mr->sgt.sgl,
- mr->sgt.nents, mr->dir);
- ib_dereg_mr(mr->mr);
- kfree(mr->sgt.sgl);
- kfree(mr);
- }
-}
-
-/*
- * Allocate MRs used for RDMA read/write
- * The number of MRs will not exceed hardware capability in responder_resources
- * All MRs are kept in mr_list. The MR can be recovered after it's used
- * Recovery is done in smbd_mr_recovery_work. The content of list entry changes
- * as MRs are used and recovered for I/O, but the list links will not change
- */
-static int allocate_mr_list(struct smbd_connection *info)
-{
- int i;
- struct smbd_mr *smbdirect_mr, *tmp;
-
- INIT_LIST_HEAD(&info->mr_list);
- init_waitqueue_head(&info->wait_mr);
- spin_lock_init(&info->mr_list_lock);
- atomic_set(&info->mr_ready_count, 0);
- atomic_set(&info->mr_used_count, 0);
- init_waitqueue_head(&info->wait_for_mr_cleanup);
- INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work);
- /* Allocate more MRs (2x) than hardware responder_resources */
- for (i = 0; i < info->responder_resources * 2; i++) {
- smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL);
- if (!smbdirect_mr)
- goto cleanup_entries;
- smbdirect_mr->mr = ib_alloc_mr(info->pd, info->mr_type,
- info->max_frmr_depth);
- if (IS_ERR(smbdirect_mr->mr)) {
- log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n",
- info->mr_type, info->max_frmr_depth);
- goto out;
- }
- smbdirect_mr->sgt.sgl = kcalloc(info->max_frmr_depth,
- sizeof(struct scatterlist),
- GFP_KERNEL);
- if (!smbdirect_mr->sgt.sgl) {
- log_rdma_mr(ERR, "failed to allocate sgl\n");
- ib_dereg_mr(smbdirect_mr->mr);
- goto out;
- }
- smbdirect_mr->state = MR_READY;
- smbdirect_mr->conn = info;
-
- list_add_tail(&smbdirect_mr->list, &info->mr_list);
- atomic_inc(&info->mr_ready_count);
- }
return 0;
-
-out:
- kfree(smbdirect_mr);
-cleanup_entries:
- list_for_each_entry_safe(smbdirect_mr, tmp, &info->mr_list, list) {
- list_del(&smbdirect_mr->list);
- ib_dereg_mr(smbdirect_mr->mr);
- kfree(smbdirect_mr->sgt.sgl);
- kfree(smbdirect_mr);
- }
- return -ENOMEM;
-}
-
-/*
- * Get a MR from mr_list. This function waits until there is at least one
- * MR available in the list. It may access the list while the
- * smbd_mr_recovery_work is recovering the MR list. This doesn't need a lock
- * as they never modify the same places. However, there may be several CPUs
- * issuing I/O trying to get MR at the same time, mr_list_lock is used to
- * protect this situation.
- */
-static struct smbd_mr *get_mr(struct smbd_connection *info)
-{
- struct smbd_mr *ret;
- int rc;
-again:
- rc = wait_event_interruptible(info->wait_mr,
- atomic_read(&info->mr_ready_count) ||
- info->transport_status != SMBD_CONNECTED);
- if (rc) {
- log_rdma_mr(ERR, "wait_event_interruptible rc=%x\n", rc);
- return NULL;
- }
-
- if (info->transport_status != SMBD_CONNECTED) {
- log_rdma_mr(ERR, "info->transport_status=%x\n",
- info->transport_status);
- return NULL;
- }
-
- spin_lock(&info->mr_list_lock);
- list_for_each_entry(ret, &info->mr_list, list) {
- if (ret->state == MR_READY) {
- ret->state = MR_REGISTERED;
- spin_unlock(&info->mr_list_lock);
- atomic_dec(&info->mr_ready_count);
- atomic_inc(&info->mr_used_count);
- return ret;
- }
- }
-
- spin_unlock(&info->mr_list_lock);
- /*
- * It is possible that we could fail to get MR because other processes may
- * try to acquire a MR at the same time. If this is the case, retry it.
- */
- goto again;
-}
-
-/*
- * Transcribe the pages from an iterator into an MR scatterlist.
- */
-static int smbd_iter_to_mr(struct smbd_connection *info,
- struct iov_iter *iter,
- struct sg_table *sgt,
- unsigned int max_sg)
-{
- int ret;
-
- memset(sgt->sgl, 0, max_sg * sizeof(struct scatterlist));
-
- ret = extract_iter_to_sg(iter, iov_iter_count(iter), sgt, max_sg, 0);
- WARN_ON(ret < 0);
- if (sgt->nents > 0)
- sg_mark_end(&sgt->sgl[sgt->nents - 1]);
- return ret;
}
/*
@@ -2243,110 +515,22 @@ static int smbd_iter_to_mr(struct smbd_connection *info,
* need_invalidate: true if this MR needs to be locally invalidated after I/O
* return value: the MR registered, NULL if failed.
*/
-struct smbd_mr *smbd_register_mr(struct smbd_connection *info,
+struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
struct iov_iter *iter,
bool writing, bool need_invalidate)
{
- struct smbd_mr *smbdirect_mr;
- int rc, num_pages;
- enum dma_data_direction dir;
- struct ib_reg_wr *reg_wr;
-
- num_pages = iov_iter_npages(iter, info->max_frmr_depth + 1);
- if (num_pages > info->max_frmr_depth) {
- log_rdma_mr(ERR, "num_pages=%d max_frmr_depth=%d\n",
- num_pages, info->max_frmr_depth);
- WARN_ON_ONCE(1);
- return NULL;
- }
+ struct smbdirect_socket *sc = info->socket;
- smbdirect_mr = get_mr(info);
- if (!smbdirect_mr) {
- log_rdma_mr(ERR, "get_mr returning NULL\n");
+ if (!smbdirect_connection_is_connected(sc))
return NULL;
- }
-
- dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- smbdirect_mr->dir = dir;
- smbdirect_mr->need_invalidate = need_invalidate;
- smbdirect_mr->sgt.nents = 0;
- smbdirect_mr->sgt.orig_nents = 0;
-
- log_rdma_mr(INFO, "num_pages=0x%x count=0x%zx depth=%u\n",
- num_pages, iov_iter_count(iter), info->max_frmr_depth);
- smbd_iter_to_mr(info, iter, &smbdirect_mr->sgt, info->max_frmr_depth);
-
- rc = ib_dma_map_sg(info->id->device, smbdirect_mr->sgt.sgl,
- smbdirect_mr->sgt.nents, dir);
- if (!rc) {
- log_rdma_mr(ERR, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n",
- num_pages, dir, rc);
- goto dma_map_error;
- }
-
- rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgt.sgl,
- smbdirect_mr->sgt.nents, NULL, PAGE_SIZE);
- if (rc != smbdirect_mr->sgt.nents) {
- log_rdma_mr(ERR,
- "ib_map_mr_sg failed rc = %d nents = %x\n",
- rc, smbdirect_mr->sgt.nents);
- goto map_mr_error;
- }
-
- ib_update_fast_reg_key(smbdirect_mr->mr,
- ib_inc_rkey(smbdirect_mr->mr->rkey));
- reg_wr = &smbdirect_mr->wr;
- reg_wr->wr.opcode = IB_WR_REG_MR;
- smbdirect_mr->cqe.done = register_mr_done;
- reg_wr->wr.wr_cqe = &smbdirect_mr->cqe;
- reg_wr->wr.num_sge = 0;
- reg_wr->wr.send_flags = IB_SEND_SIGNALED;
- reg_wr->mr = smbdirect_mr->mr;
- reg_wr->key = smbdirect_mr->mr->rkey;
- reg_wr->access = writing ?
- IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
- IB_ACCESS_REMOTE_READ;
-
- /*
- * There is no need for waiting for complemtion on ib_post_send
- * on IB_WR_REG_MR. Hardware enforces a barrier and order of execution
- * on the next ib_post_send when we actually send I/O to remote peer
- */
- rc = ib_post_send(info->id->qp, &reg_wr->wr, NULL);
- if (!rc)
- return smbdirect_mr;
-
- log_rdma_mr(ERR, "ib_post_send failed rc=%x reg_wr->key=%x\n",
- rc, reg_wr->key);
-
- /* If all failed, attempt to recover this MR by setting it MR_ERROR*/
-map_mr_error:
- ib_dma_unmap_sg(info->id->device, smbdirect_mr->sgt.sgl,
- smbdirect_mr->sgt.nents, smbdirect_mr->dir);
-
-dma_map_error:
- smbdirect_mr->state = MR_ERROR;
- if (atomic_dec_and_test(&info->mr_used_count))
- wake_up(&info->wait_for_mr_cleanup);
-
- smbd_disconnect_rdma_connection(info);
- return NULL;
+ return smbdirect_connection_register_mr_io(sc, iter, writing, need_invalidate);
}
-static void local_inv_done(struct ib_cq *cq, struct ib_wc *wc)
+void smbd_mr_fill_buffer_descriptor(struct smbdirect_mr_io *mr,
+ struct smbdirect_buffer_descriptor_v1 *v1)
{
- struct smbd_mr *smbdirect_mr;
- struct ib_cqe *cqe;
-
- cqe = wc->wr_cqe;
- smbdirect_mr = container_of(cqe, struct smbd_mr, cqe);
- smbdirect_mr->state = MR_INVALIDATED;
- if (wc->status != IB_WC_SUCCESS) {
- log_rdma_mr(ERR, "invalidate failed status=%x\n", wc->status);
- smbdirect_mr->state = MR_ERROR;
- }
- complete(&smbdirect_mr->invalidate_done);
+ smbdirect_mr_io_fill_buffer_descriptor(mr, v1);
}
/*
@@ -2355,274 +539,22 @@ static void local_inv_done(struct ib_cq *cq, struct ib_wc *wc)
* and we have to locally invalidate the buffer to prevent data is being
* modified by remote peer after upper layer consumes it
*/
-int smbd_deregister_mr(struct smbd_mr *smbdirect_mr)
-{
- struct ib_send_wr *wr;
- struct smbd_connection *info = smbdirect_mr->conn;
- int rc = 0;
-
- if (smbdirect_mr->need_invalidate) {
- /* Need to finish local invalidation before returning */
- wr = &smbdirect_mr->inv_wr;
- wr->opcode = IB_WR_LOCAL_INV;
- smbdirect_mr->cqe.done = local_inv_done;
- wr->wr_cqe = &smbdirect_mr->cqe;
- wr->num_sge = 0;
- wr->ex.invalidate_rkey = smbdirect_mr->mr->rkey;
- wr->send_flags = IB_SEND_SIGNALED;
-
- init_completion(&smbdirect_mr->invalidate_done);
- rc = ib_post_send(info->id->qp, wr, NULL);
- if (rc) {
- log_rdma_mr(ERR, "ib_post_send failed rc=%x\n", rc);
- smbd_disconnect_rdma_connection(info);
- goto done;
- }
- wait_for_completion(&smbdirect_mr->invalidate_done);
- smbdirect_mr->need_invalidate = false;
- } else
- /*
- * For remote invalidation, just set it to MR_INVALIDATED
- * and defer to mr_recovery_work to recover the MR for next use
- */
- smbdirect_mr->state = MR_INVALIDATED;
-
- if (smbdirect_mr->state == MR_INVALIDATED) {
- ib_dma_unmap_sg(
- info->id->device, smbdirect_mr->sgt.sgl,
- smbdirect_mr->sgt.nents,
- smbdirect_mr->dir);
- smbdirect_mr->state = MR_READY;
- if (atomic_inc_return(&info->mr_ready_count) == 1)
- wake_up_interruptible(&info->wait_mr);
- } else
- /*
- * Schedule the work to do MR recovery for future I/Os MR
- * recovery is slow and don't want it to block current I/O
- */
- queue_work(info->workqueue, &info->mr_recovery_work);
-
-done:
- if (atomic_dec_and_test(&info->mr_used_count))
- wake_up(&info->wait_for_mr_cleanup);
-
- return rc;
-}
-
-static bool smb_set_sge(struct smb_extract_to_rdma *rdma,
- struct page *lowest_page, size_t off, size_t len)
-{
- struct ib_sge *sge = &rdma->sge[rdma->nr_sge];
- u64 addr;
-
- addr = ib_dma_map_page(rdma->device, lowest_page,
- off, len, rdma->direction);
- if (ib_dma_mapping_error(rdma->device, addr))
- return false;
-
- sge->addr = addr;
- sge->length = len;
- sge->lkey = rdma->local_dma_lkey;
- rdma->nr_sge++;
- return true;
-}
-
-/*
- * Extract page fragments from a BVEC-class iterator and add them to an RDMA
- * element list. The pages are not pinned.
- */
-static ssize_t smb_extract_bvec_to_rdma(struct iov_iter *iter,
- struct smb_extract_to_rdma *rdma,
- ssize_t maxsize)
-{
- const struct bio_vec *bv = iter->bvec;
- unsigned long start = iter->iov_offset;
- unsigned int i;
- ssize_t ret = 0;
-
- for (i = 0; i < iter->nr_segs; i++) {
- size_t off, len;
-
- len = bv[i].bv_len;
- if (start >= len) {
- start -= len;
- continue;
- }
-
- len = min_t(size_t, maxsize, len - start);
- off = bv[i].bv_offset + start;
-
- if (!smb_set_sge(rdma, bv[i].bv_page, off, len))
- return -EIO;
-
- ret += len;
- maxsize -= len;
- if (rdma->nr_sge >= rdma->max_sge || maxsize <= 0)
- break;
- start = 0;
- }
-
- if (ret > 0)
- iov_iter_advance(iter, ret);
- return ret;
-}
-
-/*
- * Extract fragments from a KVEC-class iterator and add them to an RDMA list.
- * This can deal with vmalloc'd buffers as well as kmalloc'd or static buffers.
- * The pages are not pinned.
- */
-static ssize_t smb_extract_kvec_to_rdma(struct iov_iter *iter,
- struct smb_extract_to_rdma *rdma,
- ssize_t maxsize)
-{
- const struct kvec *kv = iter->kvec;
- unsigned long start = iter->iov_offset;
- unsigned int i;
- ssize_t ret = 0;
-
- for (i = 0; i < iter->nr_segs; i++) {
- struct page *page;
- unsigned long kaddr;
- size_t off, len, seg;
-
- len = kv[i].iov_len;
- if (start >= len) {
- start -= len;
- continue;
- }
-
- kaddr = (unsigned long)kv[i].iov_base + start;
- off = kaddr & ~PAGE_MASK;
- len = min_t(size_t, maxsize, len - start);
- kaddr &= PAGE_MASK;
-
- maxsize -= len;
- do {
- seg = min_t(size_t, len, PAGE_SIZE - off);
-
- if (is_vmalloc_or_module_addr((void *)kaddr))
- page = vmalloc_to_page((void *)kaddr);
- else
- page = virt_to_page((void *)kaddr);
-
- if (!smb_set_sge(rdma, page, off, seg))
- return -EIO;
-
- ret += seg;
- len -= seg;
- kaddr += PAGE_SIZE;
- off = 0;
- } while (len > 0 && rdma->nr_sge < rdma->max_sge);
-
- if (rdma->nr_sge >= rdma->max_sge || maxsize <= 0)
- break;
- start = 0;
- }
-
- if (ret > 0)
- iov_iter_advance(iter, ret);
- return ret;
-}
-
-/*
- * Extract folio fragments from a FOLIOQ-class iterator and add them to an RDMA
- * list. The folios are not pinned.
- */
-static ssize_t smb_extract_folioq_to_rdma(struct iov_iter *iter,
- struct smb_extract_to_rdma *rdma,
- ssize_t maxsize)
+void smbd_deregister_mr(struct smbdirect_mr_io *mr)
{
- const struct folio_queue *folioq = iter->folioq;
- unsigned int slot = iter->folioq_slot;
- ssize_t ret = 0;
- size_t offset = iter->iov_offset;
-
- BUG_ON(!folioq);
-
- if (slot >= folioq_nr_slots(folioq)) {
- folioq = folioq->next;
- if (WARN_ON_ONCE(!folioq))
- return -EIO;
- slot = 0;
- }
-
- do {
- struct folio *folio = folioq_folio(folioq, slot);
- size_t fsize = folioq_folio_size(folioq, slot);
-
- if (offset < fsize) {
- size_t part = umin(maxsize - ret, fsize - offset);
-
- if (!smb_set_sge(rdma, folio_page(folio, 0), offset, part))
- return -EIO;
-
- offset += part;
- ret += part;
- }
-
- if (offset >= fsize) {
- offset = 0;
- slot++;
- if (slot >= folioq_nr_slots(folioq)) {
- if (!folioq->next) {
- WARN_ON_ONCE(ret < iter->count);
- break;
- }
- folioq = folioq->next;
- slot = 0;
- }
- }
- } while (rdma->nr_sge < rdma->max_sge || maxsize > 0);
-
- iter->folioq = folioq;
- iter->folioq_slot = slot;
- iter->iov_offset = offset;
- iter->count -= ret;
- return ret;
+ smbdirect_connection_deregister_mr_io(mr);
}
-/*
- * Extract page fragments from up to the given amount of the source iterator
- * and build up an RDMA list that refers to all of those bits. The RDMA list
- * is appended to, up to the maximum number of elements set in the parameter
- * block.
- *
- * The extracted page fragments are not pinned or ref'd in any way; if an
- * IOVEC/UBUF-type iterator is to be used, it should be converted to a
- * BVEC-type iterator and the pages pinned, ref'd or otherwise held in some
- * way.
- */
-static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len,
- struct smb_extract_to_rdma *rdma)
+void smbd_debug_proc_show(struct TCP_Server_Info *server, struct seq_file *m)
{
- ssize_t ret;
- int before = rdma->nr_sge;
-
- switch (iov_iter_type(iter)) {
- case ITER_BVEC:
- ret = smb_extract_bvec_to_rdma(iter, rdma, len);
- break;
- case ITER_KVEC:
- ret = smb_extract_kvec_to_rdma(iter, rdma, len);
- break;
- case ITER_FOLIOQ:
- ret = smb_extract_folioq_to_rdma(iter, rdma, len);
- break;
- default:
- WARN_ON_ONCE(1);
- return -EIO;
- }
-
- if (ret < 0) {
- while (rdma->nr_sge > before) {
- struct ib_sge *sge = &rdma->sge[rdma->nr_sge--];
+ if (!server->rdma)
+ return;
- ib_dma_unmap_single(rdma->device, sge->addr, sge->length,
- rdma->direction);
- sge->addr = 0;
- }
+ if (!server->smbd_conn) {
+ seq_puts(m, "\nSMBDirect transport not available");
+ return;
}
- return ret;
+ smbdirect_connection_legacy_debug_proc_show(server->smbd_conn->socket,
+ server->rdma_readwrite_threshold,
+ m);
}
diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h
index c08e3665150d..287ac849213d 100644
--- a/fs/smb/client/smbdirect.h
+++ b/fs/smb/client/smbdirect.h
@@ -11,9 +11,8 @@
#define cifs_rdma_enabled(server) ((server)->rdma)
#include "cifsglob.h"
-#include <rdma/ib_verbs.h>
-#include <rdma/rdma_cm.h>
-#include <linux/mempool.h>
+
+#include "../smbdirect/smbdirect.h"
extern int rdma_readwrite_threshold;
extern int smbd_max_frmr_depth;
@@ -24,248 +23,16 @@ extern int smbd_max_send_size;
extern int smbd_send_credit_target;
extern int smbd_receive_credit_max;
-enum keep_alive_status {
- KEEP_ALIVE_NONE,
- KEEP_ALIVE_PENDING,
- KEEP_ALIVE_SENT,
-};
-
-enum smbd_connection_status {
- SMBD_CREATED,
- SMBD_CONNECTING,
- SMBD_CONNECTED,
- SMBD_NEGOTIATE_FAILED,
- SMBD_DISCONNECTING,
- SMBD_DISCONNECTED,
- SMBD_DESTROYED
-};
-
-/*
- * The context for the SMBDirect transport
- * Everything related to the transport is here. It has several logical parts
- * 1. RDMA related structures
- * 2. SMBDirect connection parameters
- * 3. Memory registrations
- * 4. Receive and reassembly queues for data receive path
- * 5. mempools for allocating packets
- */
struct smbd_connection {
- enum smbd_connection_status transport_status;
-
- /* RDMA related */
- struct rdma_cm_id *id;
- struct ib_qp_init_attr qp_attr;
- struct ib_pd *pd;
- struct ib_cq *send_cq, *recv_cq;
- struct ib_device_attr dev_attr;
- int ri_rc;
- struct completion ri_done;
- wait_queue_head_t conn_wait;
- wait_queue_head_t disconn_wait;
-
- struct completion negotiate_completion;
- bool negotiate_done;
-
- struct work_struct disconnect_work;
- struct work_struct post_send_credits_work;
-
- spinlock_t lock_new_credits_offered;
- int new_credits_offered;
-
- /* Connection parameters defined in [MS-SMBD] 3.1.1.1 */
- int receive_credit_max;
- int send_credit_target;
- int max_send_size;
- int max_fragmented_recv_size;
- int max_fragmented_send_size;
- int max_receive_size;
- int keep_alive_interval;
- int max_readwrite_size;
- enum keep_alive_status keep_alive_requested;
- int protocol;
- atomic_t send_credits;
- atomic_t receive_credits;
- int receive_credit_target;
- int fragment_reassembly_remaining;
-
- /* Memory registrations */
- /* Maximum number of RDMA read/write outstanding on this connection */
- int responder_resources;
- /* Maximum number of pages in a single RDMA write/read on this connection */
- int max_frmr_depth;
- /*
- * If payload is less than or equal to the threshold,
- * use RDMA send/recv to send upper layer I/O.
- * If payload is more than the threshold,
- * use RDMA read/write through memory registration for I/O.
- */
- int rdma_readwrite_threshold;
- enum ib_mr_type mr_type;
- struct list_head mr_list;
- spinlock_t mr_list_lock;
- /* The number of available MRs ready for memory registration */
- atomic_t mr_ready_count;
- atomic_t mr_used_count;
- wait_queue_head_t wait_mr;
- struct work_struct mr_recovery_work;
- /* Used by transport to wait until all MRs are returned */
- wait_queue_head_t wait_for_mr_cleanup;
-
- /* Activity accounting */
- atomic_t send_pending;
- wait_queue_head_t wait_send_pending;
- wait_queue_head_t wait_post_send;
-
- /* Receive queue */
- struct list_head receive_queue;
- int count_receive_queue;
- spinlock_t receive_queue_lock;
-
- struct list_head empty_packet_queue;
- int count_empty_packet_queue;
- spinlock_t empty_packet_queue_lock;
-
- wait_queue_head_t wait_receive_queues;
-
- /* Reassembly queue */
- struct list_head reassembly_queue;
- spinlock_t reassembly_queue_lock;
- wait_queue_head_t wait_reassembly_queue;
-
- /* total data length of reassembly queue */
- int reassembly_data_length;
- int reassembly_queue_length;
- /* the offset to first buffer in reassembly queue */
- int first_entry_offset;
-
- bool send_immediate;
-
- wait_queue_head_t wait_send_queue;
-
- /*
- * Indicate if we have received a full packet on the connection
- * This is used to identify the first SMBD packet of a assembled
- * payload (SMB packet) in reassembly queue so we can return a
- * RFC1002 length to upper layer to indicate the length of the SMB
- * packet received
- */
- bool full_packet_received;
-
- struct workqueue_struct *workqueue;
- struct delayed_work idle_timer_work;
-
- /* Memory pool for preallocating buffers */
- /* request pool for RDMA send */
- struct kmem_cache *request_cache;
- mempool_t *request_mempool;
-
- /* response pool for RDMA receive */
- struct kmem_cache *response_cache;
- mempool_t *response_mempool;
-
- /* for debug purposes */
- unsigned int count_get_receive_buffer;
- unsigned int count_put_receive_buffer;
- unsigned int count_reassembly_queue;
- unsigned int count_enqueue_reassembly_queue;
- unsigned int count_dequeue_reassembly_queue;
- unsigned int count_send_empty;
-};
-
-enum smbd_message_type {
- SMBD_NEGOTIATE_RESP,
- SMBD_TRANSFER_DATA,
-};
-
-#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001
-
-/* SMBD negotiation request packet [MS-SMBD] 2.2.1 */
-struct smbd_negotiate_req {
- __le16 min_version;
- __le16 max_version;
- __le16 reserved;
- __le16 credits_requested;
- __le32 preferred_send_size;
- __le32 max_receive_size;
- __le32 max_fragmented_size;
-} __packed;
-
-/* SMBD negotiation response packet [MS-SMBD] 2.2.2 */
-struct smbd_negotiate_resp {
- __le16 min_version;
- __le16 max_version;
- __le16 negotiated_version;
- __le16 reserved;
- __le16 credits_requested;
- __le16 credits_granted;
- __le32 status;
- __le32 max_readwrite_size;
- __le32 preferred_send_size;
- __le32 max_receive_size;
- __le32 max_fragmented_size;
-} __packed;
-
-/* SMBD data transfer packet with payload [MS-SMBD] 2.2.3 */
-struct smbd_data_transfer {
- __le16 credits_requested;
- __le16 credits_granted;
- __le16 flags;
- __le16 reserved;
- __le32 remaining_data_length;
- __le32 data_offset;
- __le32 data_length;
- __le32 padding;
- __u8 buffer[];
-} __packed;
-
-/* The packet fields for a registered RDMA buffer */
-struct smbd_buffer_descriptor_v1 {
- __le64 offset;
- __le32 token;
- __le32 length;
-} __packed;
-
-/* Maximum number of SGEs used by smbdirect.c in any send work request */
-#define SMBDIRECT_MAX_SEND_SGE 6
-
-/* The context for a SMBD request */
-struct smbd_request {
- struct smbd_connection *info;
- struct ib_cqe cqe;
-
- /* the SGE entries for this work request */
- struct ib_sge sge[SMBDIRECT_MAX_SEND_SGE];
- int num_sge;
-
- /* SMBD packet header follows this structure */
- u8 packet[];
-};
-
-/* Maximum number of SGEs used by smbdirect.c in any receive work request */
-#define SMBDIRECT_MAX_RECV_SGE 1
-
-/* The context for a SMBD response */
-struct smbd_response {
- struct smbd_connection *info;
- struct ib_cqe cqe;
- struct ib_sge sge;
-
- enum smbd_message_type type;
-
- /* Link to receive queue or reassembly queue */
- struct list_head list;
-
- /* Indicate if this is the 1st packet of a payload */
- bool first_segment;
-
- /* SMBD packet header and payload follows this structure */
- u8 packet[];
+ struct smbdirect_socket *socket;
};
/* Create a SMBDirect session */
struct smbd_connection *smbd_get_connection(
struct TCP_Server_Info *server, struct sockaddr *dstaddr);
+const struct smbdirect_socket_parameters *smbd_get_parameters(struct smbd_connection *conn);
+
/* Reconnect SMBDirect session */
int smbd_reconnect(struct TCP_Server_Info *server);
/* Destroy SMBDirect session */
@@ -276,34 +43,15 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg);
int smbd_send(struct TCP_Server_Info *server,
int num_rqst, struct smb_rqst *rqst);
-enum mr_state {
- MR_READY,
- MR_REGISTERED,
- MR_INVALIDATED,
- MR_ERROR
-};
-
-struct smbd_mr {
- struct smbd_connection *conn;
- struct list_head list;
- enum mr_state state;
- struct ib_mr *mr;
- struct sg_table sgt;
- enum dma_data_direction dir;
- union {
- struct ib_reg_wr wr;
- struct ib_send_wr inv_wr;
- };
- struct ib_cqe cqe;
- bool need_invalidate;
- struct completion invalidate_done;
-};
-
/* Interfaces to register and deregister MR for RDMA read/write */
-struct smbd_mr *smbd_register_mr(
+struct smbdirect_mr_io *smbd_register_mr(
struct smbd_connection *info, struct iov_iter *iter,
bool writing, bool need_invalidate);
-int smbd_deregister_mr(struct smbd_mr *mr);
+void smbd_mr_fill_buffer_descriptor(struct smbdirect_mr_io *mr,
+ struct smbdirect_buffer_descriptor_v1 *v1);
+void smbd_deregister_mr(struct smbdirect_mr_io *mr);
+
+void smbd_debug_proc_show(struct TCP_Server_Info *server, struct seq_file *m);
#else
#define cifs_rdma_enabled(server) 0
diff --git a/fs/smb/client/smbencrypt.c b/fs/smb/client/smbencrypt.c
index 1d1ee9f18f37..094b8296d9b4 100644
--- a/fs/smb/client/smbencrypt.c
+++ b/fs/smb/client/smbencrypt.c
@@ -20,7 +20,6 @@
#include <linux/random.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifsproto.h"
diff --git a/fs/smb/client/smberr.h b/fs/smb/client/smberr.h
index aeffdad829e2..5c3415bf18d7 100644
--- a/fs/smb/client/smberr.h
+++ b/fs/smb/client/smberr.h
@@ -9,163 +9,290 @@
*
*/
-#define SUCCESS 0x00 /* The request was successful. */
-#define ERRDOS 0x01 /* Error is from the core DOS operating system set */
-#define ERRSRV 0x02 /* Error is generated by the file server daemon */
-#define ERRHRD 0x03 /* Error is a hardware error. */
-#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+struct smb_to_posix_error {
+ __u16 smb_err;
+ int posix_code;
+};
+
+/* The request was successful. */
+#define SUCCESS 0x00
+/* Error is from the core DOS operating system set */
+#define ERRDOS 0x01
+/* Error is generated by the file server daemon */
+#define ERRSRV 0x02
+/* Error is a hardware error. */
+#define ERRHRD 0x03
+/* Command was not in the "SMB" format. */
+#define ERRCMD 0xFF
/* The following error codes may be generated with the SUCCESS error class.*/
/*#define SUCCESS 0 The request was successful. */
-/* The following error codes may be generated with the ERRDOS error class.*/
+/*
+ * The following error codes may be generated with the ERRDOS error class.
+ * The comment at the end of each definition indicates the POSIX error
+ * code; it is used to generate the `mapping_table_ERRDOS` array.
+ */
-#define ERRbadfunc 1 /* Invalid function. The server did not
- recognize or could not perform a
- system call generated by the server,
- e.g., set the DIRECTORY attribute on
- a data file, invalid seek mode. */
-#define ERRbadfile 2 /* File not found. The last component
- of a file's pathname could not be
- found. */
-#define ERRbadpath 3 /* Directory invalid. A directory
- component in a pathname could not be
- found. */
-#define ERRnofids 4 /* Too many open files. The server has
- no file handles available. */
-#define ERRnoaccess 5 /* Access denied, the client's context
- does not permit the requested
- function. This includes the
- following conditions: invalid rename
- command, write to Fid open for read
- only, read on Fid open for write
- only, attempt to delete a non-empty
- directory */
-#define ERRbadfid 6 /* Invalid file handle. The file handle
- specified was not recognized by the
- server. */
-#define ERRbadmcb 7 /* Memory control blocks destroyed. */
-#define ERRnomem 8 /* Insufficient server memory to
- perform the requested function. */
-#define ERRbadmem 9 /* Invalid memory block address. */
-#define ERRbadenv 10 /* Invalid environment. */
-#define ERRbadformat 11 /* Invalid format. */
-#define ERRbadaccess 12 /* Invalid open mode. */
-#define ERRbaddata 13 /* Invalid data (generated only by
- IOCTL calls within the server). */
-#define ERRbaddrive 15 /* Invalid drive specified. */
-#define ERRremcd 16 /* A Delete Directory request attempted
- to remove the server's current
- directory. */
-#define ERRdiffdevice 17 /* Not same device (e.g., a cross
- volume rename was attempted */
-#define ERRnofiles 18 /* A File Search command can find no
- more files matching the specified
- criteria. */
-#define ERRwriteprot 19 /* media is write protected */
+/*
+ * Invalid function. The server did not
+ * recognize or could not perform a
+ * system call generated by the server,
+ * e.g., set the DIRECTORY attribute on
+ * a data file, invalid seek mode.
+ */
+#define ERRbadfunc 1 // -EINVAL
+/*
+ * File not found. The last component
+ * of a file's pathname could not be
+ * found.
+ */
+#define ERRbadfile 2 // -ENOENT
+/*
+ * Directory invalid. A directory
+ * component in a pathname could not be
+ * found.
+ */
+#define ERRbadpath 3 // -ENOTDIR
+/*
+ * Too many open files. The server has
+ * no file handles available.
+ */
+#define ERRnofids 4 // -EMFILE
+/*
+ * Access denied, the client's context
+ * does not permit the requested
+ * function. This includes the
+ * following conditions: invalid rename
+ * command, write to Fid open for read
+ * only, read on Fid open for write
+ * only, attempt to delete a non-empty
+ * directory
+ */
+#define ERRnoaccess 5 // -EACCES
+/*
+ * Invalid file handle. The file handle
+ * specified was not recognized by the
+ * server.
+ */
+#define ERRbadfid 6 // -EBADF
+/* Memory control blocks destroyed. */
+#define ERRbadmcb 7 // -EIO
+/*
+ * Insufficient server memory to
+ * perform the requested function.
+ */
+#define ERRnomem 8 // -EREMOTEIO
+/* Invalid memory block address. */
+#define ERRbadmem 9 // -EFAULT
+/* Invalid environment. */
+#define ERRbadenv 10 // -EFAULT
+/* Invalid format. */
+#define ERRbadformat 11 // -EINVAL
+/* Invalid open mode. */
+#define ERRbadaccess 12 // -EACCES
+/*
+ * Invalid data (generated only by
+ * IOCTL calls within the server).
+ */
+#define ERRbaddata 13 // -EIO
+/* Invalid drive specified. */
+#define ERRbaddrive 15 // -ENXIO
+/*
+ * A Delete Directory request attempted
+ * to remove the server's current
+ * directory.
+ */
+#define ERRremcd 16 // -EACCES
+/*
+ * Not same device (e.g., a cross
+ * volume rename was attempted
+ */
+#define ERRdiffdevice 17 // -EXDEV
+/*
+ * A File Search command can find no
+ * more files matching the specified
+ * criteria.
+ */
+#define ERRnofiles 18 // -ENOENT
+/* media is write protected */
+#define ERRwriteprot 19 // -EROFS
#define ERRgeneral 31
-#define ERRbadshare 32 /* The sharing mode specified for an
- Open conflicts with existing FIDs on
- the file. */
-#define ERRlock 33 /* A Lock request conflicted with an
- existing lock or specified an
- invalid mode, or an Unlock requested
- attempted to remove a lock held by
- another process. */
-#define ERRunsup 50
-#define ERRnosuchshare 67
-#define ERRfilexists 80 /* The file named in the request
- already exists. */
-#define ERRinvparm 87
-#define ERRdiskfull 112
-#define ERRinvname 123
-#define ERRinvlevel 124
-#define ERRdirnotempty 145
-#define ERRnotlocked 158
-#define ERRcancelviolation 173
-#define ERRalreadyexists 183
+/*
+ * The sharing mode specified for an
+ * Open conflicts with existing FIDs on
+ * the file.
+ */
+#define ERRbadshare 32 // -EBUSY
+/*
+ * A Lock request conflicted with an
+ * existing lock or specified an
+ * invalid mode, or an Unlock requested
+ * attempted to remove a lock held by
+ * another process.
+ */
+#define ERRlock 33 // -EACCES
+#define ERRunsup 50 // -EINVAL
+#define ERRnosuchshare 67 // -ENXIO
+/*
+ * The file named in the request
+ * already exists.
+ */
+#define ERRfilexists 80 // -EEXIST
+#define ERRinvparm 87 // -EINVAL
+#define ERRdiskfull 112 // -ENOSPC
+#define ERRinvname 123 // -ENOENT
+#define ERRunknownlevel 124 // -EOPNOTSUPP
+#define ERRdirnotempty 145 // -ENOTEMPTY
+#define ERRnotlocked 158 // -ENOLCK
+#define ERRcancelviolation 173 // -ENOLCK
+#define ERRalreadyexists 183 // -EEXIST
#define ERRbadpipe 230
#define ERRpipebusy 231
#define ERRpipeclosing 232
#define ERRnotconnected 233
-#define ERRmoredata 234
-#define ERReasnotsupported 282
-#define ErrQuota 0x200 /* The operation would cause a quota
- limit to be exceeded. */
-#define ErrNotALink 0x201 /* A link operation was performed on a
- pathname that was not a link. */
+#define ERRmoredata 234 // -EOVERFLOW
+#define ERReasnotsupported 282 // -EOPNOTSUPP
+/*
+ * The operation would cause a quota
+ * limit to be exceeded.
+ */
+#define ErrQuota 0x200 // -EDQUOT
+/*
+ * A link operation was performed on a
+ * pathname that was not a link.
+ */
+#define ErrNotALink 0x201 // -ENOLINK
+#define ERRnetlogonNotStarted 2455 // -ENOPROTOOPT
/* Below errors are used internally (do not come over the wire) for passthrough
from STATUS codes to POSIX only */
-#define ERRsymlink 0xFFFD
-#define ErrTooManyLinks 0xFFFE
+#define ERRsymlink 0xFFFD // -EOPNOTSUPP
+#define ErrTooManyLinks 0xFFFE // -EMLINK
-/* Following error codes may be generated with the ERRSRV error class.*/
+/*
+ * The following error codes may be generated with the ERRSRV error class.
+ * The comment at the end of each definition indicates the POSIX error
+ * code; it is used to generate the `mapping_table_ERRSRV` array.
+ */
-#define ERRerror 1 /* Non-specific error code. It is
- returned under the following
- conditions: resource other than disk
- space exhausted (e.g. TIDs), first
- SMB command was not negotiate,
- multiple negotiates attempted, and
- internal server error. */
-#define ERRbadpw 2 /* Bad password - name/password pair in
- a TreeConnect or Session Setup are
- invalid. */
-#define ERRbadtype 3 /* used for indicating DFS referral
- needed */
-#define ERRaccess 4 /* The client does not have the
- necessary access rights within the
- specified context for requested
- function. */
-#define ERRinvtid 5 /* The Tid specified in a command was
- invalid. */
-#define ERRinvnetname 6 /* Invalid network name in tree
- connect. */
-#define ERRinvdevice 7 /* Invalid device - printer request
- made to non-printer connection or
- non-printer request made to printer
- connection. */
-#define ERRqfull 49 /* Print queue full (files) -- returned
- by open print file. */
-#define ERRqtoobig 50 /* Print queue full -- no space. */
-#define ERRqeof 51 /* EOF on print queue dump */
-#define ERRinvpfid 52 /* Invalid print file FID. */
-#define ERRsmbcmd 64 /* The server did not recognize the
- command received. */
-#define ERRsrverror 65 /* The server encountered an internal
- error, e.g., system file
- unavailable. */
-#define ERRbadBID 66 /* (obsolete) */
-#define ERRfilespecs 67 /* The Fid and pathname parameters
- contained an invalid combination of
- values. */
-#define ERRbadLink 68 /* (obsolete) */
-#define ERRbadpermits 69 /* The access permissions specified for
- a file or directory are not a valid
- combination. */
-#define ERRbadPID 70
-#define ERRsetattrmode 71 /* attribute (mode) is invalid */
-#define ERRpaused 81 /* Server is paused */
-#define ERRmsgoff 82 /* reserved - messaging off */
-#define ERRnoroom 83 /* reserved - no room for message */
-#define ERRrmuns 87 /* reserved - too many remote names */
-#define ERRtimeout 88 /* operation timed out */
-#define ERRnoresource 89 /* No resources available for request
- */
-#define ERRtoomanyuids 90 /* Too many UIDs active on this session
- */
-#define ERRbaduid 91 /* The UID is not known as a valid user
- */
-#define ERRusempx 250 /* temporarily unable to use raw */
-#define ERRusestd 251 /* temporarily unable to use either raw
- or mpx */
-#define ERR_NOTIFY_ENUM_DIR 1024
-#define ERRnoSuchUser 2238 /* user account does not exist */
-#define ERRaccountexpired 2239
-#define ERRbadclient 2240 /* can not logon from this client */
-#define ERRbadLogonTime 2241 /* logon hours do not allow this */
-#define ERRpasswordExpired 2242
-#define ERRnetlogonNotStarted 2455
-#define ERRnosupport 0xFFFF
+/*
+ * Non-specific error code. It is
+ * returned under the following
+ * conditions: resource other than disk
+ * space exhausted (e.g. TIDs), first
+ * SMB command was not negotiate,
+ * multiple negotiates attempted, and
+ * internal server error.
+ */
+#define ERRerror 1 // -EIO
+/*
+ * Bad password - name/password pair in
+ * a TreeConnect or Session Setup are
+ * invalid.
+ */
+#define ERRbadpw 2 // -EACCES
+/*
+ * used for indicating DFS referral
+ * needed
+ */
+#define ERRbadtype 3 // -EREMOTE
+/*
+ * The client does not have the
+ * necessary access rights within the
+ * specified context for requested
+ * function.
+ */
+#define ERRaccess 4 // -EACCES
+/*
+ * The Tid specified in a command was
+ * invalid.
+ */
+#define ERRinvtid 5 // -ENXIO
+/*
+ * Invalid network name in tree
+ * connect.
+ */
+#define ERRinvnetname 6 // -ENXIO
+/*
+ * Invalid device - printer request
+ * made to non-printer connection or
+ * non-printer request made to printer
+ * connection.
+ */
+#define ERRinvdevice 7 // -ENXIO
+/*
+ * Print queue full (files) -- returned
+ * by open print file.
+ */
+#define ERRqfull 49 // -ENOSPC
+/* Print queue full -- no space. */
+#define ERRqtoobig 50 // -ENOSPC
+/* EOF on print queue dump */
+#define ERRqeof 51 // -EIO
+/* Invalid print file FID. */
+#define ERRinvpfid 52 // -EBADF
+/*
+ * The server did not recognize the
+ * command received.
+ */
+#define ERRsmbcmd 64 // -EBADRQC
+/*
+ * The server encountered an internal
+ * error, e.g., system file
+ * unavailable.
+ */
+#define ERRsrverror 65 // -EIO
+/* (obsolete) */
+#define ERRbadBID 66 // -EIO
+/*
+ * The Fid and pathname parameters
+ * contained an invalid combination of
+ * values.
+ */
+#define ERRfilespecs 67 // -EINVAL
+/* (obsolete) */
+#define ERRbadLink 68 // -EIO
+/*
+ * The access permissions specified for
+ * a file or directory are not a valid
+ * combination.
+ */
+#define ERRbadpermits 69 // -EINVAL
+#define ERRbadPID 70 // -ESRCH
+/* attribute (mode) is invalid */
+#define ERRsetattrmode 71 // -EINVAL
+/* Server is paused */
+#define ERRpaused 81 // -EHOSTDOWN
+/* reserved - messaging off */
+#define ERRmsgoff 82 // -EHOSTDOWN
+/* reserved - no room for message */
+#define ERRnoroom 83 // -ENOSPC
+/* reserved - too many remote names */
+#define ERRrmuns 87 // -EUSERS
+/* operation timed out */
+#define ERRtimeout 88 // -ETIME
+/* No resources available for request */
+#define ERRnoresource 89 // -EREMOTEIO
+/* Too many UIDs active on this session */
+#define ERRtoomanyuids 90 // -EUSERS
+/* The UID is not known as a valid user */
+#define ERRbaduid 91 // -EACCES
+/* temporarily unable to use raw */
+#define ERRusempx 250 // -EIO
+/*
+ * temporarily unable to use either raw
+ * or mpx
+ */
+#define ERRusestd 251 // -EIO
+#define ERR_NOTIFY_ENUM_DIR 1024 // -ENOBUFS
+/* user account does not exist */
+#define ERRnoSuchUser 2238 // -EACCES
+#define ERRaccountexpired 2239 // -EKEYEXPIRED
+/* can not logon from this client */
+#define ERRbadclient 2240 // -EACCES
+/* logon hours do not allow this */
+#define ERRbadLogonTime 2241 // -EACCES
+#define ERRpasswordExpired 2242 // -EKEYEXPIRED
+#define ERRnosupport 0xFFFF // -EINVAL
diff --git a/fs/smb/client/trace.c b/fs/smb/client/trace.c
index 465483787193..8a99b68d0c71 100644
--- a/fs/smb/client/trace.c
+++ b/fs/smb/client/trace.c
@@ -4,5 +4,7 @@
*
* Author(s): Steve French <stfrench@microsoft.com>
*/
+#include "cifsglob.h"
+#include "cifs_spnego.h"
#define CREATE_TRACE_POINTS
#include "trace.h"
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 52bcb55d9952..b99ec5a417fa 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -20,6 +20,136 @@
/*
* Specify enums for tracing information.
*/
+#define smb_eio_traces \
+ EM(smb_eio_trace_compress_copy, "compress_copy") \
+ EM(smb_eio_trace_copychunk_inv_rsp, "copychunk_inv_rsp") \
+ EM(smb_eio_trace_copychunk_overcopy_b, "copychunk_overcopy_b") \
+ EM(smb_eio_trace_copychunk_overcopy_c, "copychunk_overcopy_c") \
+ EM(smb_eio_trace_create_rsp_too_small, "create_rsp_too_small") \
+ EM(smb_eio_trace_dfsref_no_rsp, "dfsref_no_rsp") \
+ EM(smb_eio_trace_ea_overrun, "ea_overrun") \
+ EM(smb_eio_trace_extract_will_pin, "extract_will_pin") \
+ EM(smb_eio_trace_forced_shutdown, "forced_shutdown") \
+ EM(smb_eio_trace_getacl_bcc_too_small, "getacl_bcc_too_small") \
+ EM(smb_eio_trace_getcifsacl_param_count, "getcifsacl_param_count") \
+ EM(smb_eio_trace_getdfsrefer_bcc_too_small, "getdfsrefer_bcc_too_small") \
+ EM(smb_eio_trace_getextattr_bcc_too_small, "getextattr_bcc_too_small") \
+ EM(smb_eio_trace_getextattr_inv_size, "getextattr_inv_size") \
+ EM(smb_eio_trace_getsrvinonum_bcc_too_small, "getsrvinonum_bcc_too_small") \
+ EM(smb_eio_trace_getsrvinonum_size, "getsrvinonum_size") \
+ EM(smb_eio_trace_ioctl_data_len, "ioctl_data_len") \
+ EM(smb_eio_trace_ioctl_no_rsp, "ioctl_no_rsp") \
+ EM(smb_eio_trace_ioctl_out_off, "ioctl_out_off") \
+ EM(smb_eio_trace_lock_bcc_too_small, "lock_bcc_too_small") \
+ EM(smb_eio_trace_lock_data_too_small, "lock_data_too_small") \
+ EM(smb_eio_trace_malformed_ksid_key, "malformed_ksid_key") \
+ EM(smb_eio_trace_malformed_sid_key, "malformed_sid_key") \
+ EM(smb_eio_trace_mkdir_no_rsp, "mkdir_no_rsp") \
+ EM(smb_eio_trace_neg_bad_rsplen, "neg_bad_rsplen") \
+ EM(smb_eio_trace_neg_decode_token, "neg_decode_token") \
+ EM(smb_eio_trace_neg_info_caps, "neg_info_caps") \
+ EM(smb_eio_trace_neg_info_dialect, "neg_info_dialect") \
+ EM(smb_eio_trace_neg_info_fail, "neg_info_fail") \
+ EM(smb_eio_trace_neg_info_sec_mode, "neg_info_sec_mode") \
+ EM(smb_eio_trace_neg_inval_dialect, "neg_inval_dialect") \
+ EM(smb_eio_trace_neg_no_crypt_key, "neg_no_crypt_key") \
+ EM(smb_eio_trace_neg_sec_blob_too_small, "neg_sec_blob_too_small") \
+ EM(smb_eio_trace_neg_unreq_dialect, "neg_unreq_dialect") \
+ EM(smb_eio_trace_no_auth_key, "no_auth_key") \
+ EM(smb_eio_trace_no_lease_key, "no_lease_key") \
+ EM(smb_eio_trace_not_netfs_writeback, "not_netfs_writeback") \
+ EM(smb_eio_trace_null_pointers, "null_pointers") \
+ EM(smb_eio_trace_oldqfsinfo_bcc_too_small, "oldqfsinfo_bcc_too_small") \
+ EM(smb_eio_trace_pend_del_fail, "pend_del_fail") \
+ EM(smb_eio_trace_qalleas_bcc_too_small, "qalleas_bcc_too_small") \
+ EM(smb_eio_trace_qalleas_ea_overlong, "qalleas_ea_overlong") \
+ EM(smb_eio_trace_qalleas_overlong, "qalleas_overlong") \
+ EM(smb_eio_trace_qfileinfo_bcc_too_small, "qfileinfo_bcc_too_small") \
+ EM(smb_eio_trace_qfileinfo_invalid, "qfileinfo_invalid") \
+ EM(smb_eio_trace_qfsattrinfo_bcc_too_small, "qfsattrinfo_bcc_too_small") \
+ EM(smb_eio_trace_qfsdevinfo_bcc_too_small, "qfsdevinfo_bcc_too_small") \
+ EM(smb_eio_trace_qfsinfo_bcc_too_small, "qfsinfo_bcc_too_small") \
+ EM(smb_eio_trace_qfsposixinfo_bcc_too_small, "qfsposixinfo_bcc_too_small") \
+ EM(smb_eio_trace_qfsunixinfo_bcc_too_small, "qfsunixinfo_bcc_too_small") \
+ EM(smb_eio_trace_qpathinfo_bcc_too_small, "qpathinfo_bcc_too_small") \
+ EM(smb_eio_trace_qpathinfo_invalid, "qpathinfo_invalid") \
+ EM(smb_eio_trace_qreparse_data_area, "qreparse_data_area") \
+ EM(smb_eio_trace_qreparse_rep_datalen, "qreparse_rep_datalen") \
+ EM(smb_eio_trace_qreparse_ret_datalen, "qreparse_ret_datalen") \
+ EM(smb_eio_trace_qreparse_setup_count, "qreparse_setup_count") \
+ EM(smb_eio_trace_qreparse_sizes_wrong, "qreparse_sizes_wrong") \
+ EM(smb_eio_trace_qsym_bcc_too_small, "qsym_bcc_too_small") \
+ EM(smb_eio_trace_read_mid_state_unknown, "read_mid_state_unknown") \
+ EM(smb_eio_trace_read_overlarge, "read_overlarge") \
+ EM(smb_eio_trace_read_rsp_malformed, "read_rsp_malformed") \
+ EM(smb_eio_trace_read_rsp_short, "read_rsp_short") \
+ EM(smb_eio_trace_read_too_far, "read_too_far") \
+ EM(smb_eio_trace_reparse_data_len, "reparse_data_len") \
+ EM(smb_eio_trace_reparse_native_len, "reparse_native_len") \
+ EM(smb_eio_trace_reparse_native_nul, "reparse_native_nul") \
+ EM(smb_eio_trace_reparse_native_sym_len, "reparse_native_sym_len") \
+ EM(smb_eio_trace_reparse_nfs_dev, "reparse_nfs_dev") \
+ EM(smb_eio_trace_reparse_nfs_nul, "reparse_nfs_nul") \
+ EM(smb_eio_trace_reparse_nfs_sockfifo, "reparse_nfs_sockfifo") \
+ EM(smb_eio_trace_reparse_nfs_symbuf, "reparse_nfs_symbuf") \
+ EM(smb_eio_trace_reparse_nfs_too_short, "reparse_nfs_too_short") \
+ EM(smb_eio_trace_reparse_overlong, "reparse_overlong") \
+ EM(smb_eio_trace_reparse_rdlen, "reparse_rdlen") \
+ EM(smb_eio_trace_reparse_wsl_nul, "reparse_wsl_nul") \
+ EM(smb_eio_trace_reparse_wsl_symbuf, "reparse_wsl_symbuf") \
+ EM(smb_eio_trace_reparse_wsl_ver, "reparse_wsl_ver") \
+ EM(smb_eio_trace_rx_b_read_short, "rx_b_read_short") \
+ EM(smb_eio_trace_rx_bad_datalen, "rx_bad_datalen") \
+ EM(smb_eio_trace_rx_both_buf, "rx_both_buf") \
+ EM(smb_eio_trace_rx_calc_len_too_big, "rx_calc_len_too_big") \
+ EM(smb_eio_trace_rx_check_rsp, "rx_check_rsp") \
+ EM(smb_eio_trace_rx_copy_to_iter, "rx_copy_to_iter") \
+ EM(smb_eio_trace_rx_insuff_res, "rx_insuff_res") \
+ EM(smb_eio_trace_rx_inv_bcc, "rx_inv_bcc") \
+ EM(smb_eio_trace_rx_mid_unready, "rx_mid_unready") \
+ EM(smb_eio_trace_rx_neg_sess_resp, "rx_neg_sess_resp") \
+ EM(smb_eio_trace_rx_overlong, "rx_overlong") \
+ EM(smb_eio_trace_rx_overpage, "rx_overpage") \
+ EM(smb_eio_trace_rx_pos_sess_resp, "rx_pos_sess_resp") \
+ EM(smb_eio_trace_rx_rfc1002_magic, "rx_rfc1002_magic") \
+ EM(smb_eio_trace_rx_sync_mid_invalid, "rx_sync_mid_invalid") \
+ EM(smb_eio_trace_rx_sync_mid_malformed, "rx_sync_mid_malformed") \
+ EM(smb_eio_trace_rx_too_short, "rx_too_short") \
+ EM(smb_eio_trace_rx_trans2_extract, "rx_trans2_extract") \
+ EM(smb_eio_trace_rx_unknown_resp, "rx_unknown_resp") \
+ EM(smb_eio_trace_rx_unspec_error, "rx_unspec_error") \
+ EM(smb_eio_trace_sess_buf_off, "sess_buf_off") \
+ EM(smb_eio_trace_sess_exiting, "sess_exiting") \
+ EM(smb_eio_trace_sess_krb_wcc, "sess_krb_wcc") \
+ EM(smb_eio_trace_sess_nl2_wcc, "sess_nl2_wcc") \
+ EM(smb_eio_trace_sess_rawnl_auth_wcc, "sess_rawnl_auth_wcc") \
+ EM(smb_eio_trace_sess_rawnl_neg_wcc, "sess_rawnl_neg_wcc") \
+ EM(smb_eio_trace_short_symlink_write, "short_symlink_write") \
+ EM(smb_eio_trace_sid_too_many_auth, "sid_too_many_auth") \
+ EM(smb_eio_trace_sig_data_too_small, "sig_data_too_small") \
+ EM(smb_eio_trace_sig_iter, "sig_iter") \
+ EM(smb_eio_trace_smb1_received_error, "smb1_received_error") \
+ EM(smb_eio_trace_smb2_received_error, "smb2_received_error") \
+ EM(smb_eio_trace_sym_slash, "sym_slash") \
+ EM(smb_eio_trace_sym_target_len, "sym_target_len") \
+ EM(smb_eio_trace_symlink_file_size, "symlink_file_size") \
+ EM(smb_eio_trace_tdis_in_reconnect, "tdis_in_reconnect") \
+ EM(smb_eio_trace_tx_chained_async, "tx_chained_async") \
+ EM(smb_eio_trace_tx_compress_failed, "tx_compress_failed") \
+ EM(smb_eio_trace_tx_copy_iter_to_buf, "tx_copy_iter_to_buf") \
+ EM(smb_eio_trace_tx_copy_to_buf, "tx_copy_to_buf") \
+ EM(smb_eio_trace_tx_max_compound, "tx_max_compound") \
+ EM(smb_eio_trace_tx_miscopy_to_buf, "tx_miscopy_to_buf") \
+ EM(smb_eio_trace_tx_need_transform, "tx_need_transform") \
+ EM(smb_eio_trace_tx_too_long, "sr_too_long") \
+ EM(smb_eio_trace_unixqfileinfo_bcc_too_small, "unixqfileinfo_bcc_too_small") \
+ EM(smb_eio_trace_unixqpathinfo_bcc_too_small, "unixqpathinfo_bcc_too_small") \
+ EM(smb_eio_trace_user_iter, "user_iter") \
+ EM(smb_eio_trace_write_bad_buf_type, "write_bad_buf_type") \
+ EM(smb_eio_trace_write_mid_state_unknown, "write_mid_state_unknown") \
+ EM(smb_eio_trace_write_rsp_malformed, "write_rsp_malformed") \
+ E_(smb_eio_trace_write_too_far, "write_too_far")
+
#define smb3_rw_credits_traces \
EM(cifs_trace_rw_credits_call_readv_adjust, "rd-call-adj") \
EM(cifs_trace_rw_credits_call_writev_adjust, "wr-call-adj") \
@@ -38,7 +168,6 @@
E_(cifs_trace_rw_credits_zero_in_flight, "ZERO-IN-FLT")
#define smb3_tcon_ref_traces \
- EM(netfs_trace_tcon_ref_dec_dfs_refer, "DEC DfsRef") \
EM(netfs_trace_tcon_ref_free, "FRE ") \
EM(netfs_trace_tcon_ref_free_fail, "FRE Fail ") \
EM(netfs_trace_tcon_ref_free_ipc, "FRE Ipc ") \
@@ -47,6 +176,7 @@
EM(netfs_trace_tcon_ref_get_cached_laundromat, "GET Ch-Lau") \
EM(netfs_trace_tcon_ref_get_cached_lease_break, "GET Ch-Lea") \
EM(netfs_trace_tcon_ref_get_cancelled_close, "GET Cn-Cls") \
+ EM(netfs_trace_tcon_ref_get_close_defer_files, "GET Cl-Def") \
EM(netfs_trace_tcon_ref_get_dfs_refer, "GET DfsRef") \
EM(netfs_trace_tcon_ref_get_find, "GET Find ") \
EM(netfs_trace_tcon_ref_get_find_sess_tcon, "GET FndSes") \
@@ -58,7 +188,9 @@
EM(netfs_trace_tcon_ref_put_cancelled_close, "PUT Cn-Cls") \
EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \
EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \
+ EM(netfs_trace_tcon_ref_put_close_defer_files, "PUT Cl-Def") \
EM(netfs_trace_tcon_ref_put_mnt_ctx, "PUT MntCtx") \
+ EM(netfs_trace_tcon_ref_put_dfs_refer, "PUT DfsRfr") \
EM(netfs_trace_tcon_ref_put_reconnect_server, "PUT Reconn") \
EM(netfs_trace_tcon_ref_put_tlink, "PUT Tlink ") \
EM(netfs_trace_tcon_ref_see_cancelled_close, "SEE Cn-Cls") \
@@ -79,6 +211,7 @@
#define EM(a, b) a,
#define E_(a, b) a
+enum smb_eio_trace { smb_eio_traces } __mode(byte);
enum smb3_rw_credits_trace { smb3_rw_credits_traces } __mode(byte);
enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte);
@@ -92,6 +225,7 @@ enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte);
#define EM(a, b) TRACE_DEFINE_ENUM(a);
#define E_(a, b) TRACE_DEFINE_ENUM(a);
+smb_eio_traces;
smb3_rw_credits_traces;
smb3_tcon_ref_traces;
@@ -140,7 +274,7 @@ DECLARE_EVENT_CLASS(smb3_rw_err_class,
__entry->len = len;
__entry->rc = rc;
),
- TP_printk("\tR=%08x[%x] xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d",
+ TP_printk("R=%08x[%x] xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d",
__entry->rreq_debug_id, __entry->rreq_debug_index,
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
__entry->offset, __entry->len, __entry->rc)
@@ -190,7 +324,7 @@ DECLARE_EVENT_CLASS(smb3_other_err_class,
__entry->len = len;
__entry->rc = rc;
),
- TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d",
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
__entry->offset, __entry->len, __entry->rc)
)
@@ -247,7 +381,7 @@ DECLARE_EVENT_CLASS(smb3_copy_range_err_class,
__entry->len = len;
__entry->rc = rc;
),
- TP_printk("\txid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x rc=%d",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x rc=%d",
__entry->xid, __entry->sesid, __entry->tid, __entry->target_fid,
__entry->src_offset, __entry->target_fid, __entry->target_offset, __entry->len, __entry->rc)
)
@@ -266,7 +400,7 @@ DEFINE_EVENT(smb3_copy_range_err_class, smb3_##name, \
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len, rc))
DEFINE_SMB3_COPY_RANGE_ERR_EVENT(clone_err);
-/* TODO: Add SMB3_COPY_RANGE_ERR_EVENT(copychunk_err) */
+DEFINE_SMB3_COPY_RANGE_ERR_EVENT(copychunk_err);
DECLARE_EVENT_CLASS(smb3_copy_range_done_class,
TP_PROTO(unsigned int xid,
@@ -298,7 +432,7 @@ DECLARE_EVENT_CLASS(smb3_copy_range_done_class,
__entry->target_offset = target_offset;
__entry->len = len;
),
- TP_printk("\txid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x",
__entry->xid, __entry->sesid, __entry->tid, __entry->target_fid,
__entry->src_offset, __entry->target_fid, __entry->target_offset, __entry->len)
)
@@ -482,7 +616,7 @@ DECLARE_EVENT_CLASS(smb3_fd_class,
__entry->tid = tid;
__entry->sesid = sesid;
),
- TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx",
__entry->xid, __entry->sesid, __entry->tid, __entry->fid)
)
@@ -521,7 +655,7 @@ DECLARE_EVENT_CLASS(smb3_fd_err_class,
__entry->sesid = sesid;
__entry->rc = rc;
),
- TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx rc=%d",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx rc=%d",
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
__entry->rc)
)
@@ -536,9 +670,100 @@ DEFINE_EVENT(smb3_fd_err_class, smb3_##name, \
TP_ARGS(xid, fid, tid, sesid, rc))
DEFINE_SMB3_FD_ERR_EVENT(flush_err);
-DEFINE_SMB3_FD_ERR_EVENT(lock_err);
DEFINE_SMB3_FD_ERR_EVENT(close_err);
+DECLARE_EVENT_CLASS(smb3_lock_class,
+ TP_PROTO(unsigned int xid,
+ __u64 fid,
+ __u32 tid,
+ __u64 sesid,
+ __u64 offset,
+ __u64 len,
+ __u32 flags,
+ __u32 num_lock,
+ int rc),
+ TP_ARGS(xid, fid, tid, sesid, offset, len, flags, num_lock, rc),
+ TP_STRUCT__entry(
+ __field(unsigned int, xid)
+ __field(__u64, fid)
+ __field(__u32, tid)
+ __field(__u64, sesid)
+ __field(__u64, offset)
+ __field(__u64, len)
+ __field(__u32, flags)
+ __field(__u32, num_lock)
+ __field(int, rc)
+ ),
+ TP_fast_assign(
+ __entry->xid = xid;
+ __entry->fid = fid;
+ __entry->tid = tid;
+ __entry->sesid = sesid;
+ __entry->offset = offset;
+ __entry->len = len;
+ __entry->flags = flags;
+ __entry->num_lock = num_lock;
+ __entry->rc = rc;
+ ),
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%llx flags=0x%x num_lock=%u rc=%d",
+ __entry->xid, __entry->sesid, __entry->tid, __entry->fid,
+ __entry->offset, __entry->len, __entry->flags, __entry->num_lock,
+ __entry->rc)
+)
+
+#define DEFINE_SMB3_LOCK_EVENT(name) \
+DEFINE_EVENT(smb3_lock_class, smb3_##name, \
+ TP_PROTO(unsigned int xid, \
+ __u64 fid, \
+ __u32 tid, \
+ __u64 sesid, \
+ __u64 offset, \
+ __u64 len, \
+ __u32 flags, \
+ __u32 num_lock, \
+ int rc), \
+ TP_ARGS(xid, fid, tid, sesid, offset, len, flags, num_lock, rc))
+
+DEFINE_SMB3_LOCK_EVENT(lock_enter);
+DEFINE_SMB3_LOCK_EVENT(lock_done);
+DEFINE_SMB3_LOCK_EVENT(lock_err);
+DEFINE_SMB3_LOCK_EVENT(lock_cached);
+
+TRACE_EVENT(smb3_lock_conflict,
+ TP_PROTO(__u64 fid,
+ __u64 req_offset,
+ __u64 req_len,
+ __u8 req_type,
+ __u64 conf_offset,
+ __u64 conf_len,
+ __u16 conf_type,
+ __u32 conf_pid),
+ TP_ARGS(fid, req_offset, req_len, req_type, conf_offset, conf_len, conf_type, conf_pid),
+ TP_STRUCT__entry(
+ __field(__u64, fid)
+ __field(__u64, req_offset)
+ __field(__u64, req_len)
+ __field(__u8, req_type)
+ __field(__u64, conf_offset)
+ __field(__u64, conf_len)
+ __field(__u16, conf_type)
+ __field(__u32, conf_pid)
+ ),
+ TP_fast_assign(
+ __entry->fid = fid;
+ __entry->req_offset = req_offset;
+ __entry->req_len = req_len;
+ __entry->req_type = req_type;
+ __entry->conf_offset = conf_offset;
+ __entry->conf_len = conf_len;
+ __entry->conf_type = conf_type;
+ __entry->conf_pid = conf_pid;
+ ),
+ TP_printk("fid=0x%llx req=[0x%llx:0x%llx] type=0x%x conflicts with [0x%llx:0x%llx] type=0x%x pid=%u",
+ __entry->fid, __entry->req_offset, __entry->req_len, __entry->req_type,
+ __entry->conf_offset, __entry->conf_len, __entry->conf_type, __entry->conf_pid)
+);
+
/*
* For handle based query/set info calls
*/
@@ -669,13 +894,12 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_info_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(posix_query_info_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(hardlink_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter);
-DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter);
+DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(unlink_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_wsl_ea_compound_enter);
-DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mknod_enter);
@@ -710,13 +934,12 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_info_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(posix_query_info_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(hardlink_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done);
-DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done);
+DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(unlink_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_wsl_ea_compound_done);
-DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mknod_done);
@@ -756,14 +979,13 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_info_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(posix_query_info_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(hardlink_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err);
-DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err);
+DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(unlink_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_wsl_ea_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err);
-DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mknod_err);
@@ -794,7 +1016,7 @@ DECLARE_EVENT_CLASS(smb3_cmd_err_class,
__entry->status = status;
__entry->rc = rc;
),
- TP_printk("\tsid=0x%llx tid=0x%x cmd=%u mid=%llu status=0x%x rc=%d",
+ TP_printk("sid=0x%llx tid=0x%x cmd=%u mid=%llu status=0x%x rc=%d",
__entry->sesid, __entry->tid, __entry->cmd, __entry->mid,
__entry->status, __entry->rc)
)
@@ -829,7 +1051,7 @@ DECLARE_EVENT_CLASS(smb3_cmd_done_class,
__entry->cmd = cmd;
__entry->mid = mid;
),
- TP_printk("\tsid=0x%llx tid=0x%x cmd=%u mid=%llu",
+ TP_printk("sid=0x%llx tid=0x%x cmd=%u mid=%llu",
__entry->sesid, __entry->tid,
__entry->cmd, __entry->mid)
)
@@ -867,7 +1089,7 @@ DECLARE_EVENT_CLASS(smb3_mid_class,
__entry->when_sent = when_sent;
__entry->when_received = when_received;
),
- TP_printk("\tcmd=%u mid=%llu pid=%u, when_sent=%lu when_rcv=%lu",
+ TP_printk("cmd=%u mid=%llu pid=%u, when_sent=%lu when_rcv=%lu",
__entry->cmd, __entry->mid, __entry->pid, __entry->when_sent,
__entry->when_received)
)
@@ -898,7 +1120,7 @@ DECLARE_EVENT_CLASS(smb3_exit_err_class,
__assign_str(func_name);
__entry->rc = rc;
),
- TP_printk("\t%s: xid=%u rc=%d",
+ TP_printk("%s: xid=%u rc=%d",
__get_str(func_name), __entry->xid, __entry->rc)
)
@@ -924,7 +1146,7 @@ DECLARE_EVENT_CLASS(smb3_sync_err_class,
__entry->ino = ino;
__entry->rc = rc;
),
- TP_printk("\tino=%lu rc=%d",
+ TP_printk("ino=%lu rc=%d",
__entry->ino, __entry->rc)
)
@@ -950,7 +1172,7 @@ DECLARE_EVENT_CLASS(smb3_enter_exit_class,
__entry->xid = xid;
__assign_str(func_name);
),
- TP_printk("\t%s: xid=%u",
+ TP_printk("%s: xid=%u",
__get_str(func_name), __entry->xid)
)
@@ -1099,8 +1321,9 @@ DECLARE_EVENT_CLASS(smb3_open_done_class,
__u32 tid,
__u64 sesid,
int create_options,
- int desired_access),
- TP_ARGS(xid, fid, tid, sesid, create_options, desired_access),
+ int desired_access,
+ __u8 oplock),
+ TP_ARGS(xid, fid, tid, sesid, create_options, desired_access, oplock),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u64, fid)
@@ -1108,6 +1331,7 @@ DECLARE_EVENT_CLASS(smb3_open_done_class,
__field(__u64, sesid)
__field(int, create_options)
__field(int, desired_access)
+ __field(__u8, oplock)
),
TP_fast_assign(
__entry->xid = xid;
@@ -1116,10 +1340,11 @@ DECLARE_EVENT_CLASS(smb3_open_done_class,
__entry->sesid = sesid;
__entry->create_options = create_options;
__entry->desired_access = desired_access;
+ __entry->oplock = oplock;
),
- TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx cr_opts=0x%x des_access=0x%x",
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx cr_opts=0x%x des_access=0x%x oplock=0x%x",
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
- __entry->create_options, __entry->desired_access)
+ __entry->create_options, __entry->desired_access, __entry->oplock)
)
#define DEFINE_SMB3_OPEN_DONE_EVENT(name) \
@@ -1129,12 +1354,64 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
__u32 tid, \
__u64 sesid, \
int create_options, \
- int desired_access), \
- TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
+ int desired_access, \
+ __u8 oplock), \
+ TP_ARGS(xid, fid, tid, sesid, create_options, desired_access, oplock))
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
+TRACE_EVENT(smb3_open_cached,
+ TP_PROTO(unsigned int xid,
+ __u32 tid,
+ __u64 sesid,
+ __u64 fid,
+ unsigned int oflags,
+ unsigned int cflags),
+ TP_ARGS(xid, tid, sesid, fid, oflags, cflags),
+ TP_STRUCT__entry(
+ __field(unsigned int, xid)
+ __field(__u32, tid)
+ __field(__u64, sesid)
+ __field(__u64, fid)
+ __field(unsigned int, oflags)
+ __field(unsigned int, cflags)
+ ),
+ TP_fast_assign(
+ __entry->xid = xid;
+ __entry->tid = tid;
+ __entry->sesid = sesid;
+ __entry->fid = fid;
+ __entry->oflags = oflags;
+ __entry->cflags = cflags;
+ ),
+ TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx oflags=0x%x cflags=0x%x",
+ __entry->xid, __entry->sesid, __entry->tid, __entry->fid,
+ __entry->oflags, __entry->cflags)
+);
+
+TRACE_EVENT(smb3_close_cached,
+ TP_PROTO(__u32 tid,
+ __u64 sesid,
+ __u64 fid,
+ unsigned long delay_jiffies),
+ TP_ARGS(tid, sesid, fid, delay_jiffies),
+ TP_STRUCT__entry(
+ __field(__u32, tid)
+ __field(__u64, sesid)
+ __field(__u64, fid)
+ __field(unsigned long, delay_jiffies)
+ ),
+ TP_fast_assign(
+ __entry->tid = tid;
+ __entry->sesid = sesid;
+ __entry->fid = fid;
+ __entry->delay_jiffies = delay_jiffies;
+ ),
+ TP_printk("sid=0x%llx tid=0x%x fid=0x%llx delay_jiffies=%lu",
+ __entry->sesid, __entry->tid, __entry->fid, __entry->delay_jiffies)
+);
+
DECLARE_EVENT_CLASS(smb3_lease_done_class,
TP_PROTO(__u32 lease_state,
@@ -1171,8 +1448,54 @@ DEFINE_EVENT(smb3_lease_done_class, smb3_##name, \
__u64 lease_key_high), \
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high))
-DEFINE_SMB3_LEASE_DONE_EVENT(lease_done);
-DEFINE_SMB3_LEASE_DONE_EVENT(lease_not_found);
+DEFINE_SMB3_LEASE_DONE_EVENT(lease_ack_done);
+/* Tracepoint when a lease break request is received/entered (includes epoch and flags) */
+DECLARE_EVENT_CLASS(smb3_lease_enter_class,
+ TP_PROTO(__u32 lease_state,
+ __u32 flags,
+ __u16 epoch,
+ __u32 tid,
+ __u64 sesid,
+ __u64 lease_key_low,
+ __u64 lease_key_high),
+ TP_ARGS(lease_state, flags, epoch, tid, sesid, lease_key_low, lease_key_high),
+ TP_STRUCT__entry(
+ __field(__u32, lease_state)
+ __field(__u32, flags)
+ __field(__u16, epoch)
+ __field(__u32, tid)
+ __field(__u64, sesid)
+ __field(__u64, lease_key_low)
+ __field(__u64, lease_key_high)
+ ),
+ TP_fast_assign(
+ __entry->lease_state = lease_state;
+ __entry->flags = flags;
+ __entry->epoch = epoch;
+ __entry->tid = tid;
+ __entry->sesid = sesid;
+ __entry->lease_key_low = lease_key_low;
+ __entry->lease_key_high = lease_key_high;
+ ),
+ TP_printk("sid=0x%llx tid=0x%x lease_key=0x%llx%llx lease_state=0x%x flags=0x%x epoch=%u",
+ __entry->sesid, __entry->tid, __entry->lease_key_high,
+ __entry->lease_key_low, __entry->lease_state, __entry->flags, __entry->epoch)
+)
+
+#define DEFINE_SMB3_LEASE_ENTER_EVENT(name) \
+DEFINE_EVENT(smb3_lease_enter_class, smb3_##name, \
+ TP_PROTO(__u32 lease_state, \
+ __u32 flags, \
+ __u16 epoch, \
+ __u32 tid, \
+ __u64 sesid, \
+ __u64 lease_key_low, \
+ __u64 lease_key_high), \
+ TP_ARGS(lease_state, flags, epoch, tid, sesid, lease_key_low, lease_key_high))
+
+DEFINE_SMB3_LEASE_ENTER_EVENT(lease_break_enter);
+/* Lease not found: reuse lease_enter payload (includes epoch and flags) */
+DEFINE_SMB3_LEASE_ENTER_EVENT(lease_not_found);
DECLARE_EVENT_CLASS(smb3_lease_err_class,
TP_PROTO(__u32 lease_state,
@@ -1213,7 +1536,7 @@ DEFINE_EVENT(smb3_lease_err_class, smb3_##name, \
int rc), \
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high, rc))
-DEFINE_SMB3_LEASE_ERR_EVENT(lease_err);
+DEFINE_SMB3_LEASE_ERR_EVENT(lease_ack_err);
DECLARE_EVENT_CLASS(smb3_connect_class,
TP_PROTO(char *hostname,
@@ -1404,6 +1727,7 @@ DEFINE_EVENT(smb3_ioctl_class, smb3_##name, \
TP_ARGS(xid, fid, command))
DEFINE_SMB3_IOCTL_EVENT(ioctl);
+DEFINE_SMB3_IOCTL_EVENT(unsupported_ioctl);
DECLARE_EVENT_CLASS(smb3_shutdown_class,
TP_PROTO(__u32 flags,
@@ -1517,6 +1841,49 @@ DEFINE_SMB3_CREDIT_EVENT(waitff_credits);
DEFINE_SMB3_CREDIT_EVENT(overflow_credits);
DEFINE_SMB3_CREDIT_EVENT(set_credits);
+TRACE_EVENT(smb3_kerberos_auth,
+ TP_PROTO(struct TCP_Server_Info *server,
+ struct cifs_ses *ses,
+ int rc),
+ TP_ARGS(server, ses, rc),
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(uid_t, uid)
+ __field(uid_t, cruid)
+ __string(host, server->hostname)
+ __string(user, ses->user_name)
+ __array(__u8, addr, sizeof(struct sockaddr_storage))
+ __array(char, sec, sizeof("ntlmsspi"))
+ __array(char, upcall_target, sizeof("mount"))
+ __field(int, rc)
+ ),
+ TP_fast_assign(
+ __entry->pid = current->pid;
+ __entry->uid = from_kuid_munged(&init_user_ns, ses->linux_uid);
+ __entry->cruid = from_kuid_munged(&init_user_ns, ses->cred_uid);
+ __assign_str(host);
+ __assign_str(user);
+ memcpy(__entry->addr, &server->dstaddr, sizeof(__entry->addr));
+
+ if (server->sec_kerberos)
+ memcpy(__entry->sec, "krb5", sizeof("krb5"));
+ else if (server->sec_mskerberos)
+ memcpy(__entry->sec, "mskrb5", sizeof("mskrb5"));
+ else if (server->sec_iakerb)
+ memcpy(__entry->sec, "iakerb", sizeof("iakerb"));
+ else
+ memcpy(__entry->sec, "krb5", sizeof("krb5"));
+
+ if (ses->upcall_target == UPTARGET_MOUNT)
+ memcpy(__entry->upcall_target, "mount", sizeof("mount"));
+ else
+ memcpy(__entry->upcall_target, "app", sizeof("app"));
+ __entry->rc = rc;
+ ),
+ TP_printk("vers=%d host=%s ip=%pISpsfc sec=%s uid=%d cruid=%d user=%s pid=%d upcall_target=%s err=%d",
+ CIFS_SPNEGO_UPCALL_VERSION, __get_str(host), __entry->addr,
+ __entry->sec, __entry->uid, __entry->cruid, __get_str(user),
+ __entry->pid, __entry->upcall_target, __entry->rc))
TRACE_EVENT(smb3_tcon_ref,
TP_PROTO(unsigned int tcon_debug_id, int ref,
@@ -1573,6 +1940,23 @@ TRACE_EVENT(smb3_rw_credits,
__entry->server_credits, __entry->in_flight)
);
+TRACE_EVENT(smb3_eio,
+ TP_PROTO(enum smb_eio_trace trace, unsigned long info, unsigned long info2),
+ TP_ARGS(trace, info, info2),
+ TP_STRUCT__entry(
+ __field(enum smb_eio_trace, trace)
+ __field(unsigned long, info)
+ __field(unsigned long, info2)
+ ),
+ TP_fast_assign(
+ __entry->trace = trace;
+ __entry->info = info;
+ __entry->info2 = info2;
+ ),
+ TP_printk("%s info=%lx,%lx",
+ __print_symbolic(__entry->trace, smb_eio_traces),
+ __entry->info, __entry->info2)
+ );
#undef EM
#undef E_
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 266af17aa7d9..05f8099047e1 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -22,7 +22,7 @@
#include <linux/mempool.h>
#include <linux/sched/signal.h>
#include <linux/task_io_accounting_ops.h>
-#include "cifspdu.h"
+#include <linux/task_work.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -30,66 +30,24 @@
#include "smbdirect.h"
#include "compress.h"
-/* Max number of iovectors we can use off the stack when sending requests. */
-#define CIFS_MAX_IOV_SIZE 8
-
void
-cifs_wake_up_task(struct mid_q_entry *mid)
+cifs_wake_up_task(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
if (mid->mid_state == MID_RESPONSE_RECEIVED)
mid->mid_state = MID_RESPONSE_READY;
wake_up_process(mid->callback_data);
}
-static struct mid_q_entry *
-alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
+void __release_mid(struct TCP_Server_Info *server, struct mid_q_entry *midEntry)
{
- struct mid_q_entry *temp;
-
- if (server == NULL) {
- cifs_dbg(VFS, "%s: null TCP session\n", __func__);
- return NULL;
- }
-
- temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
- memset(temp, 0, sizeof(struct mid_q_entry));
- kref_init(&temp->refcount);
- temp->mid = get_mid(smb_buffer);
- temp->pid = current->pid;
- temp->command = cpu_to_le16(smb_buffer->Command);
- cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
- /* easier to use jiffies */
- /* when mid allocated can be before when sent */
- temp->when_alloc = jiffies;
- temp->server = server;
-
- /*
- * The default is for the mid to be synchronous, so the
- * default callback just wakes up the current task.
- */
- get_task_struct(current);
- temp->creator = current;
- temp->callback = cifs_wake_up_task;
- temp->callback_data = current;
-
- atomic_inc(&mid_count);
- temp->mid_state = MID_REQUEST_ALLOCATED;
- return temp;
-}
-
-void __release_mid(struct kref *refcount)
-{
- struct mid_q_entry *midEntry =
- container_of(refcount, struct mid_q_entry, refcount);
#ifdef CONFIG_CIFS_STATS2
- __le16 command = midEntry->server->vals->lock_cmd;
+ __le16 command = server->vals->lock_cmd;
__u16 smb_cmd = le16_to_cpu(midEntry->command);
unsigned long now;
unsigned long roundtrip_time;
#endif
- struct TCP_Server_Info *server = midEntry->server;
- if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
+ if (midEntry->resp_buf && (midEntry->wait_cancelled) &&
(midEntry->mid_state == MID_RESPONSE_RECEIVED ||
midEntry->mid_state == MID_RESPONSE_READY) &&
server->ops->handle_cancelled_mid)
@@ -154,20 +112,21 @@ void __release_mid(struct kref *refcount)
#endif
put_task_struct(midEntry->creator);
- mempool_free(midEntry, cifs_mid_poolp);
+ mempool_free(midEntry, &cifs_mid_pool);
}
void
-delete_mid(struct mid_q_entry *mid)
+delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- spin_lock(&mid->server->mid_lock);
- if (!(mid->mid_flags & MID_DELETED)) {
+ spin_lock(&server->mid_queue_lock);
+
+ if (!mid->deleted_from_q) {
list_del_init(&mid->qhead);
- mid->mid_flags |= MID_DELETED;
+ mid->deleted_from_q = true;
}
- spin_unlock(&mid->server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
- release_mid(mid);
+ release_mid(server, mid);
}
/*
@@ -212,9 +171,16 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
* send a packet. In most cases if we fail to send
* after the retries we will kill the socket and
* reconnect which may clear the network problem.
+ *
+ * Even if regular signals are masked, EINTR might be
+ * propagated from sk_stream_wait_memory() to here when
+ * TIF_NOTIFY_SIGNAL is used for task work. For example,
+ * certain io_uring completions will use that. Treat
+ * having EINTR with pending task work the same as EAGAIN
+ * to avoid unnecessary reconnects.
*/
rc = sock_sendmsg(ssocket, smb_msg);
- if (rc == -EAGAIN) {
+ if (rc == -EAGAIN || unlikely(rc == -EINTR && task_work_pending(current))) {
retries++;
if (retries >= 14 ||
(!server->noblocksnd && (retries > 2))) {
@@ -269,9 +235,8 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
return buflen;
}
-static int
-__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
- struct smb_rqst *rqst)
+int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
+ struct smb_rqst *rqst)
{
int rc;
struct kvec *iov;
@@ -321,8 +286,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
sigfillset(&mask);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
- /* Generate a rfc1002 marker for SMB2+ */
- if (!is_smb1(server)) {
+ /* Generate a rfc1002 marker */
+ {
struct kvec hiov = {
.iov_base = &rfc1002_marker,
.iov_len = 4
@@ -363,8 +328,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
break;
total_len += sent;
}
-
-}
+ }
unmask:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
@@ -397,7 +361,7 @@ unmask:
* socket so the server throws away the partial SMB
*/
cifs_signal_cifsd_for_reconnect(server, false);
- trace_smb3_partial_send_reconnect(server->CurrentMid,
+ trace_smb3_partial_send_reconnect(server->current_mid,
server->conn_id, server->hostname);
}
smbd_done:
@@ -437,11 +401,11 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
return __smb_send_rqst(server, num_rqst, rqst);
if (WARN_ON_ONCE(num_rqst > MAX_COMPOUND - 1))
- return -EIO;
+ return smb_EIO1(smb_eio_trace_tx_max_compound, num_rqst);
if (!server->ops->init_transform_rq) {
cifs_server_dbg(VFS, "Encryption requested but transform callback is missing\n");
- return -EIO;
+ return smb_EIO(smb_eio_trace_tx_need_transform);
}
new_rqst[0].rq_iov = &iov;
@@ -456,22 +420,6 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
return rc;
}
-int
-smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
- unsigned int smb_buf_length)
-{
- struct kvec iov[2];
- struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = 2 };
-
- iov[0].iov_base = smb_buffer;
- iov[0].iov_len = 4;
- iov[1].iov_base = (char *)smb_buffer + 4;
- iov[1].iov_len = smb_buf_length;
-
- return __smb_send_rqst(server, 1, &rqst);
-}
-
static int
wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
const int timeout, const int flags,
@@ -509,7 +457,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
- trace_smb3_nblk_credits(server->CurrentMid,
+ trace_smb3_nblk_credits(server->current_mid,
server->conn_id, server->hostname, scredits, -1, in_flight);
cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
__func__, 1, scredits);
@@ -542,7 +490,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
- trace_smb3_credit_timeout(server->CurrentMid,
+ trace_smb3_credit_timeout(server->current_mid,
server->conn_id, server->hostname, scredits,
num_credits, in_flight);
cifs_server_dbg(VFS, "wait timed out after %d ms\n",
@@ -585,7 +533,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
spin_unlock(&server->req_lock);
trace_smb3_credit_timeout(
- server->CurrentMid,
+ server->current_mid,
server->conn_id, server->hostname,
scredits, num_credits, in_flight);
cifs_server_dbg(VFS, "wait timed out after %d ms\n",
@@ -615,7 +563,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
- trace_smb3_waitff_credits(server->CurrentMid,
+ trace_smb3_waitff_credits(server->current_mid,
server->conn_id, server->hostname, scredits,
-(num_credits), in_flight);
cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
@@ -626,9 +574,8 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
return 0;
}
-static int
-wait_for_free_request(struct TCP_Server_Info *server, const int flags,
- unsigned int *instance)
+int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
+ unsigned int *instance)
{
return wait_for_free_credits(server, 1, -1, flags,
instance);
@@ -666,7 +613,7 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
*/
if (server->in_flight == 0) {
spin_unlock(&server->req_lock);
- trace_smb3_insufficient_credits(server->CurrentMid,
+ trace_smb3_insufficient_credits(server->current_mid,
server->conn_id, server->hostname, scredits,
num, in_flight);
cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n",
@@ -690,89 +637,32 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
return 0;
}
-static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
- struct mid_q_entry **ppmidQ)
-{
- spin_lock(&ses->ses_lock);
- if (ses->ses_status == SES_NEW) {
- if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
- (in_buf->Command != SMB_COM_NEGOTIATE)) {
- spin_unlock(&ses->ses_lock);
- return -EAGAIN;
- }
- /* else ok - we are setting up session */
- }
-
- if (ses->ses_status == SES_EXITING) {
- /* check if SMB session is bad because we are setting it up */
- if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
- spin_unlock(&ses->ses_lock);
- return -EAGAIN;
- }
- /* else ok - we are shutting down session */
- }
- spin_unlock(&ses->ses_lock);
-
- *ppmidQ = alloc_mid(in_buf, ses->server);
- if (*ppmidQ == NULL)
- return -ENOMEM;
- spin_lock(&ses->server->mid_lock);
- list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
- spin_unlock(&ses->server->mid_lock);
- return 0;
-}
-
-static int
-wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
+int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
+ unsigned int sleep_state = TASK_KILLABLE;
int error;
+ if (mid->sr_flags & CIFS_INTERRUPTIBLE_WAIT)
+ sleep_state = TASK_INTERRUPTIBLE;
+
error = wait_event_state(server->response_q,
- midQ->mid_state != MID_REQUEST_SUBMITTED &&
- midQ->mid_state != MID_RESPONSE_RECEIVED,
- (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
+ mid->mid_state != MID_REQUEST_SUBMITTED &&
+ mid->mid_state != MID_RESPONSE_RECEIVED,
+ (sleep_state | TASK_FREEZABLE_UNSAFE));
if (error < 0)
return -ERESTARTSYS;
return 0;
}
-struct mid_q_entry *
-cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
-{
- int rc;
- struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
- struct mid_q_entry *mid;
-
- if (rqst->rq_iov[0].iov_len != 4 ||
- rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
- return ERR_PTR(-EIO);
-
- /* enable signing if server requires it */
- if (server->sign)
- hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
- mid = alloc_mid(hdr, server);
- if (mid == NULL)
- return ERR_PTR(-ENOMEM);
-
- rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
- if (rc) {
- release_mid(mid);
- return ERR_PTR(rc);
- }
-
- return mid;
-}
-
/*
* Send a SMB request and set the callback function in the mid to handle
* the result. Caller is responsible for dealing with timeouts.
*/
int
cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
- mid_receive_t *receive, mid_callback_t *callback,
- mid_handle_t *handle, void *cbdata, const int flags,
+ mid_receive_t receive, mid_callback_t callback,
+ mid_handle_t handle, void *cbdata, const int flags,
const struct cifs_credits *exist_credits)
{
int rc;
@@ -812,6 +702,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
return PTR_ERR(mid);
}
+ mid->sr_flags = flags;
mid->receive = receive;
mid->callback = callback;
mid->callback_data = cbdata;
@@ -819,9 +710,9 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
mid->mid_state = MID_REQUEST_SUBMITTED;
/* put it on the pending_mid_q */
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
list_add_tail(&mid->qhead, &server->pending_mid_q);
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
/*
* Need to store the time in mid before calling I/O. For call_async,
@@ -833,7 +724,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
if (rc < 0) {
revert_current_mid(server, mid->credits);
server->sequence_number -= 2;
- delete_mid(mid);
+ delete_mid(server, mid);
}
cifs_server_unlock(server);
@@ -845,51 +736,23 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
return rc;
}
-/*
- *
- * Send an SMB Request. No response info (other than return code)
- * needs to be parsed.
- *
- * flags indicate the type of request buffer and how long to wait
- * and whether to log NT STATUS code (error) before mapping it to POSIX error
- *
- */
-int
-SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
- char *in_buf, int flags)
-{
- int rc;
- struct kvec iov[1];
- struct kvec rsp_iov;
- int resp_buf_type;
-
- iov[0].iov_base = in_buf;
- iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
- flags |= CIFS_NO_RSP_BUF;
- rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
- cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
-
- return rc;
-}
-
-static int
-cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
{
int rc = 0;
cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
__func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state);
- spin_lock(&server->mid_lock);
+ spin_lock(&server->mid_queue_lock);
switch (mid->mid_state) {
case MID_RESPONSE_READY:
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
return rc;
case MID_RETRY_NEEDED:
rc = -EAGAIN;
break;
case MID_RESPONSE_MALFORMED:
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_rx_sync_mid_malformed);
break;
case MID_SHUTDOWN:
rc = -EHOSTDOWN;
@@ -898,89 +761,26 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
rc = mid->mid_rc;
break;
default:
- if (!(mid->mid_flags & MID_DELETED)) {
+ if (mid->deleted_from_q == false) {
list_del_init(&mid->qhead);
- mid->mid_flags |= MID_DELETED;
+ mid->deleted_from_q = true;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
__func__, mid->mid, mid->mid_state);
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_rx_sync_mid_invalid, mid->mid_state);
goto sync_mid_done;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&server->mid_queue_lock);
sync_mid_done:
- release_mid(mid);
+ release_mid(server, mid);
return rc;
}
-static inline int
-send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
- struct mid_q_entry *mid)
-{
- return server->ops->send_cancel ?
- server->ops->send_cancel(server, rqst, mid) : 0;
-}
-
-int
-cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
- bool log_error)
-{
- unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
-
- dump_smb(mid->resp_buf, min_t(u32, 92, len));
-
- /* convert the length into a more usable form */
- if (server->sign) {
- struct kvec iov[2];
- int rc = 0;
- struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = 2 };
-
- iov[0].iov_base = mid->resp_buf;
- iov[0].iov_len = 4;
- iov[1].iov_base = (char *)mid->resp_buf + 4;
- iov[1].iov_len = len - 4;
- /* FIXME: add code to kill session */
- rc = cifs_verify_signature(&rqst, server,
- mid->sequence_number);
- if (rc)
- cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
- rc);
- }
-
- /* BB special case reconnect tid and uid here? */
- return map_and_check_smb_error(mid, log_error);
-}
-
-struct mid_q_entry *
-cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
- struct smb_rqst *rqst)
-{
- int rc;
- struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
- struct mid_q_entry *mid;
-
- if (rqst->rq_iov[0].iov_len != 4 ||
- rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
- return ERR_PTR(-EIO);
-
- rc = allocate_mid(ses, hdr, &mid);
- if (rc)
- return ERR_PTR(rc);
- rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
- if (rc) {
- delete_mid(mid);
- return ERR_PTR(rc);
- }
- return mid;
-}
-
static void
-cifs_compound_callback(struct mid_q_entry *mid)
+cifs_compound_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- struct TCP_Server_Info *server = mid->server;
struct cifs_credits credits = {
.value = server->ops->get_credits(mid),
.instance = server->reconnect_instance,
@@ -993,43 +793,50 @@ cifs_compound_callback(struct mid_q_entry *mid)
}
static void
-cifs_compound_last_callback(struct mid_q_entry *mid)
+cifs_compound_last_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- cifs_compound_callback(mid);
- cifs_wake_up_task(mid);
+ cifs_compound_callback(server, mid);
+ cifs_wake_up_task(server, mid);
}
static void
-cifs_cancelled_callback(struct mid_q_entry *mid)
+cifs_cancelled_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- cifs_compound_callback(mid);
- release_mid(mid);
+ cifs_compound_callback(server, mid);
+ release_mid(server, mid);
}
/*
- * Return a channel (master if none) of @ses that can be used to send
- * regular requests.
+ * cifs_pick_channel - pick an eligible channel for network operations
+ *
+ * @ses: session reference
*
- * If we are currently binding a new channel (negprot/sess.setup),
- * return the new incomplete channel.
+ * Select an eligible channel (not terminating and not marked as needing
+ * reconnect), preferring the least loaded one. If no eligible channel is
+ * found, fall back to the primary channel (index 0).
+ *
+ * Return: TCP_Server_Info pointer for the chosen channel, or NULL if @ses is
+ * NULL.
*/
struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
{
uint index = 0;
- unsigned int min_in_flight = UINT_MAX, max_in_flight = 0;
+ unsigned int min_in_flight = UINT_MAX;
struct TCP_Server_Info *server = NULL;
- int i;
+ int i, start, cur;
if (!ses)
return NULL;
spin_lock(&ses->chan_lock);
+ start = atomic_inc_return(&ses->chan_seq);
for (i = 0; i < ses->chan_count; i++) {
- server = ses->chans[i].server;
+ cur = (start + i) % ses->chan_count;
+ server = ses->chans[cur].server;
if (!server || server->terminate)
continue;
- if (CIFS_CHAN_NEEDS_RECONNECT(ses, i))
+ if (CIFS_CHAN_NEEDS_RECONNECT(ses, cur))
continue;
/*
@@ -1042,16 +849,8 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
*/
if (server->in_flight < min_in_flight) {
min_in_flight = server->in_flight;
- index = i;
+ index = cur;
}
- if (server->in_flight > max_in_flight)
- max_in_flight = server->in_flight;
- }
-
- /* if all channels are equally loaded, fall back to round-robin */
- if (min_in_flight == max_in_flight) {
- index = (uint)atomic_inc_return(&ses->chan_seq);
- index %= ses->chan_count;
}
server = ses->chans[index].server;
@@ -1067,7 +866,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
int *resp_buf_type, struct kvec *resp_iov)
{
int i, j, optype, rc = 0;
- struct mid_q_entry *midQ[MAX_COMPOUND];
+ struct mid_q_entry *mid[MAX_COMPOUND];
bool cancelled_mid[MAX_COMPOUND] = {false};
struct cifs_credits credits[MAX_COMPOUND] = {
{ .value = 0, .instance = 0 }
@@ -1082,7 +881,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
if (!ses || !ses->server || !server) {
cifs_dbg(VFS, "Null session\n");
- return -EIO;
+ return smb_EIO(smb_eio_trace_null_pointers);
}
spin_lock(&server->srv_lock);
@@ -1133,35 +932,36 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
}
for (i = 0; i < num_rqst; i++) {
- midQ[i] = server->ops->setup_request(ses, server, &rqst[i]);
- if (IS_ERR(midQ[i])) {
+ mid[i] = server->ops->setup_request(ses, server, &rqst[i]);
+ if (IS_ERR(mid[i])) {
revert_current_mid(server, i);
for (j = 0; j < i; j++)
- delete_mid(midQ[j]);
+ delete_mid(server, mid[j]);
cifs_server_unlock(server);
/* Update # of requests on wire to server */
for (j = 0; j < num_rqst; j++)
add_credits(server, &credits[j], optype);
- return PTR_ERR(midQ[i]);
+ return PTR_ERR(mid[i]);
}
- midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
- midQ[i]->optype = optype;
+ mid[i]->sr_flags = flags;
+ mid[i]->mid_state = MID_REQUEST_SUBMITTED;
+ mid[i]->optype = optype;
/*
* Invoke callback for every part of the compound chain
* to calculate credits properly. Wake up this thread only when
* the last element is received.
*/
if (i < num_rqst - 1)
- midQ[i]->callback = cifs_compound_callback;
+ mid[i]->callback = cifs_compound_callback;
else
- midQ[i]->callback = cifs_compound_last_callback;
+ mid[i]->callback = cifs_compound_last_callback;
}
rc = smb_send_rqst(server, num_rqst, rqst, flags);
for (i = 0; i < num_rqst; i++)
- cifs_save_when_sent(midQ[i]);
+ cifs_save_when_sent(mid[i]);
if (rc < 0) {
revert_current_mid(server, num_rqst);
@@ -1195,6 +995,9 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
spin_unlock(&ses->ses_lock);
+ if (WARN_ON_ONCE(num_rqst != 1 || !resp_iov))
+ return -EINVAL;
+
cifs_server_lock(server);
smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
cifs_server_unlock(server);
@@ -1204,24 +1007,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
spin_unlock(&ses->ses_lock);
for (i = 0; i < num_rqst; i++) {
- rc = wait_for_response(server, midQ[i]);
+ rc = wait_for_response(server, mid[i]);
if (rc != 0)
break;
}
if (rc != 0) {
for (; i < num_rqst; i++) {
cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
- midQ[i]->mid, le16_to_cpu(midQ[i]->command));
- send_cancel(server, &rqst[i], midQ[i]);
- spin_lock(&server->mid_lock);
- midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
- if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
- midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
- midQ[i]->callback = cifs_cancelled_callback;
+ mid[i]->mid, le16_to_cpu(mid[i]->command));
+ send_cancel(ses, server, &rqst[i], mid[i], xid);
+ spin_lock(&mid[i]->mid_lock);
+ mid[i]->wait_cancelled = true;
+ if (mid[i]->mid_state == MID_REQUEST_SUBMITTED ||
+ mid[i]->mid_state == MID_RESPONSE_RECEIVED) {
+ mid[i]->callback = cifs_cancelled_callback;
cancelled_mid[i] = true;
credits[i].value = 0;
}
- spin_unlock(&server->mid_lock);
+ spin_unlock(&mid[i]->mid_lock);
}
}
@@ -1229,37 +1032,37 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
if (rc < 0)
goto out;
- rc = cifs_sync_mid_result(midQ[i], server);
+ rc = cifs_sync_mid_result(mid[i], server);
if (rc != 0) {
/* mark this mid as cancelled to not free it below */
cancelled_mid[i] = true;
goto out;
}
- if (!midQ[i]->resp_buf ||
- midQ[i]->mid_state != MID_RESPONSE_READY) {
- rc = -EIO;
+ if (!mid[i]->resp_buf ||
+ mid[i]->mid_state != MID_RESPONSE_READY) {
+ rc = smb_EIO1(smb_eio_trace_rx_mid_unready, mid[i]->mid_state);
cifs_dbg(FYI, "Bad MID state?\n");
goto out;
}
- buf = (char *)midQ[i]->resp_buf;
- resp_iov[i].iov_base = buf;
- resp_iov[i].iov_len = midQ[i]->resp_buf_size +
- HEADER_PREAMBLE_SIZE(server);
+ rc = server->ops->check_receive(mid[i], server,
+ flags & CIFS_LOG_ERROR);
- if (midQ[i]->large_buf)
- resp_buf_type[i] = CIFS_LARGE_BUFFER;
- else
- resp_buf_type[i] = CIFS_SMALL_BUFFER;
+ if (resp_iov) {
+ buf = (char *)mid[i]->resp_buf;
+ resp_iov[i].iov_base = buf;
+ resp_iov[i].iov_len = mid[i]->resp_buf_size;
- rc = server->ops->check_receive(midQ[i], server,
- flags & CIFS_LOG_ERROR);
-
- /* mark it so buf will not be freed by delete_mid */
- if ((flags & CIFS_NO_RSP_BUF) == 0)
- midQ[i]->resp_buf = NULL;
+ if (mid[i]->large_buf)
+ resp_buf_type[i] = CIFS_LARGE_BUFFER;
+ else
+ resp_buf_type[i] = CIFS_SMALL_BUFFER;
+ /* mark it so buf will not be freed by delete_mid */
+ if ((flags & CIFS_NO_RSP_BUF) == 0)
+ mid[i]->resp_buf = NULL;
+ }
}
/*
@@ -1288,7 +1091,7 @@ out:
*/
for (i = 0; i < num_rqst; i++) {
if (!cancelled_mid[i])
- delete_mid(midQ[i]);
+ delete_mid(server, mid[i]);
}
return rc;
@@ -1304,344 +1107,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
rqst, resp_buf_type, resp_iov);
}
-int
-SendReceive2(const unsigned int xid, struct cifs_ses *ses,
- struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
- const int flags, struct kvec *resp_iov)
-{
- struct smb_rqst rqst;
- struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
- int rc;
-
- if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
- new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
- GFP_KERNEL);
- if (!new_iov) {
- /* otherwise cifs_send_recv below sets resp_buf_type */
- *resp_buf_type = CIFS_NO_BUFFER;
- return -ENOMEM;
- }
- } else
- new_iov = s_iov;
-
- /* 1st iov is a RFC1001 length followed by the rest of the packet */
- memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
-
- new_iov[0].iov_base = new_iov[1].iov_base;
- new_iov[0].iov_len = 4;
- new_iov[1].iov_base += 4;
- new_iov[1].iov_len -= 4;
-
- memset(&rqst, 0, sizeof(struct smb_rqst));
- rqst.rq_iov = new_iov;
- rqst.rq_nvec = n_vec + 1;
-
- rc = cifs_send_recv(xid, ses, ses->server,
- &rqst, resp_buf_type, flags, resp_iov);
- if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
- kfree(new_iov);
- return rc;
-}
-
-int
-SendReceive(const unsigned int xid, struct cifs_ses *ses,
- struct smb_hdr *in_buf, struct smb_hdr *out_buf,
- int *pbytes_returned, const int flags)
-{
- int rc = 0;
- struct mid_q_entry *midQ;
- unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
- struct kvec iov = { .iov_base = in_buf, .iov_len = len };
- struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
- struct cifs_credits credits = { .value = 1, .instance = 0 };
- struct TCP_Server_Info *server;
-
- if (ses == NULL) {
- cifs_dbg(VFS, "Null smb session\n");
- return -EIO;
- }
- server = ses->server;
- if (server == NULL) {
- cifs_dbg(VFS, "Null tcp session\n");
- return -EIO;
- }
-
- spin_lock(&server->srv_lock);
- if (server->tcpStatus == CifsExiting) {
- spin_unlock(&server->srv_lock);
- return -ENOENT;
- }
- spin_unlock(&server->srv_lock);
-
- /* Ensure that we do not send more than 50 overlapping requests
- to the same server. We may make this configurable later or
- use ses->maxReq */
-
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
- len);
- return -EIO;
- }
-
- rc = wait_for_free_request(server, flags, &credits.instance);
- if (rc)
- return rc;
-
- /* make sure that we sign in the same order that we send on this socket
- and avoid races inside tcp sendmsg code that could cause corruption
- of smb data */
-
- cifs_server_lock(server);
-
- rc = allocate_mid(ses, in_buf, &midQ);
- if (rc) {
- cifs_server_unlock(server);
- /* Update # of requests on wire to server */
- add_credits(server, &credits, 0);
- return rc;
- }
-
- rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
- if (rc) {
- cifs_server_unlock(server);
- goto out;
- }
-
- midQ->mid_state = MID_REQUEST_SUBMITTED;
-
- rc = smb_send(server, in_buf, len);
- cifs_save_when_sent(midQ);
-
- if (rc < 0)
- server->sequence_number -= 2;
-
- cifs_server_unlock(server);
-
- if (rc < 0)
- goto out;
-
- rc = wait_for_response(server, midQ);
- if (rc != 0) {
- send_cancel(server, &rqst, midQ);
- spin_lock(&server->mid_lock);
- if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED) {
- /* no longer considered to be "in-flight" */
- midQ->callback = release_mid;
- spin_unlock(&server->mid_lock);
- add_credits(server, &credits, 0);
- return rc;
- }
- spin_unlock(&server->mid_lock);
- }
-
- rc = cifs_sync_mid_result(midQ, server);
- if (rc != 0) {
- add_credits(server, &credits, 0);
- return rc;
- }
-
- if (!midQ->resp_buf || !out_buf ||
- midQ->mid_state != MID_RESPONSE_READY) {
- rc = -EIO;
- cifs_server_dbg(VFS, "Bad MID state?\n");
- goto out;
- }
-
- *pbytes_returned = get_rfc1002_length(midQ->resp_buf);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
- rc = cifs_check_receive(midQ, server, 0);
-out:
- delete_mid(midQ);
- add_credits(server, &credits, 0);
-
- return rc;
-}
-
-/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
- blocking lock to return. */
-
-static int
-send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
- struct smb_hdr *in_buf,
- struct smb_hdr *out_buf)
-{
- int bytes_returned;
- struct cifs_ses *ses = tcon->ses;
- LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
-
- /* We just modify the current in_buf to change
- the type of lock from LOCKING_ANDX_SHARED_LOCK
- or LOCKING_ANDX_EXCLUSIVE_LOCK to
- LOCKING_ANDX_CANCEL_LOCK. */
-
- pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
- pSMB->Timeout = 0;
- pSMB->hdr.Mid = get_next_mid(ses->server);
-
- return SendReceive(xid, ses, in_buf, out_buf,
- &bytes_returned, 0);
-}
-
-int
-SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
- struct smb_hdr *in_buf, struct smb_hdr *out_buf,
- int *pbytes_returned)
-{
- int rc = 0;
- int rstart = 0;
- struct mid_q_entry *midQ;
- struct cifs_ses *ses;
- unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
- struct kvec iov = { .iov_base = in_buf, .iov_len = len };
- struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
- unsigned int instance;
- struct TCP_Server_Info *server;
-
- if (tcon == NULL || tcon->ses == NULL) {
- cifs_dbg(VFS, "Null smb session\n");
- return -EIO;
- }
- ses = tcon->ses;
- server = ses->server;
-
- if (server == NULL) {
- cifs_dbg(VFS, "Null tcp session\n");
- return -EIO;
- }
-
- spin_lock(&server->srv_lock);
- if (server->tcpStatus == CifsExiting) {
- spin_unlock(&server->srv_lock);
- return -ENOENT;
- }
- spin_unlock(&server->srv_lock);
-
- /* Ensure that we do not send more than 50 overlapping requests
- to the same server. We may make this configurable later or
- use ses->maxReq */
-
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
- len);
- return -EIO;
- }
-
- rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
- if (rc)
- return rc;
-
- /* make sure that we sign in the same order that we send on this socket
- and avoid races inside tcp sendmsg code that could cause corruption
- of smb data */
-
- cifs_server_lock(server);
-
- rc = allocate_mid(ses, in_buf, &midQ);
- if (rc) {
- cifs_server_unlock(server);
- return rc;
- }
-
- rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
- if (rc) {
- delete_mid(midQ);
- cifs_server_unlock(server);
- return rc;
- }
-
- midQ->mid_state = MID_REQUEST_SUBMITTED;
- rc = smb_send(server, in_buf, len);
- cifs_save_when_sent(midQ);
-
- if (rc < 0)
- server->sequence_number -= 2;
-
- cifs_server_unlock(server);
-
- if (rc < 0) {
- delete_mid(midQ);
- return rc;
- }
-
- /* Wait for a reply - allow signals to interrupt. */
- rc = wait_event_interruptible(server->response_q,
- (!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
- ((server->tcpStatus != CifsGood) &&
- (server->tcpStatus != CifsNew)));
-
- /* Were we interrupted by a signal ? */
- spin_lock(&server->srv_lock);
- if ((rc == -ERESTARTSYS) &&
- (midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED) &&
- ((server->tcpStatus == CifsGood) ||
- (server->tcpStatus == CifsNew))) {
- spin_unlock(&server->srv_lock);
-
- if (in_buf->Command == SMB_COM_TRANSACTION2) {
- /* POSIX lock. We send a NT_CANCEL SMB to cause the
- blocking lock to return. */
- rc = send_cancel(server, &rqst, midQ);
- if (rc) {
- delete_mid(midQ);
- return rc;
- }
- } else {
- /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
- to cause the blocking lock to return. */
-
- rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
-
- /* If we get -ENOLCK back the lock may have
- already been removed. Don't exit in this case. */
- if (rc && rc != -ENOLCK) {
- delete_mid(midQ);
- return rc;
- }
- }
-
- rc = wait_for_response(server, midQ);
- if (rc) {
- send_cancel(server, &rqst, midQ);
- spin_lock(&server->mid_lock);
- if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED) {
- /* no longer considered to be "in-flight" */
- midQ->callback = release_mid;
- spin_unlock(&server->mid_lock);
- return rc;
- }
- spin_unlock(&server->mid_lock);
- }
-
- /* We got the response - restart system call. */
- rstart = 1;
- spin_lock(&server->srv_lock);
- }
- spin_unlock(&server->srv_lock);
-
- rc = cifs_sync_mid_result(midQ, server);
- if (rc != 0)
- return rc;
-
- /* rcvd frame is ok */
- if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
- rc = -EIO;
- cifs_tcon_dbg(VFS, "Bad MID state?\n");
- goto out;
- }
-
- *pbytes_returned = get_rfc1002_length(midQ->resp_buf);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
- rc = cifs_check_receive(midQ, server, 0);
-out:
- delete_mid(midQ);
- if (rstart && rc == -EACCES)
- return -ERESTARTSYS;
- return rc;
-}
/*
* Discard any remaining data in the current SMB. To do this, we borrow the
@@ -1651,8 +1116,7 @@ int
cifs_discard_remaining_data(struct TCP_Server_Info *server)
{
unsigned int rfclen = server->pdu_size;
- size_t remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
- server->total_read;
+ size_t remaining = rfclen - server->total_read;
while (remaining > 0) {
ssize_t length;
@@ -1676,7 +1140,7 @@ __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
int length;
length = cifs_discard_remaining_data(server);
- dequeue_mid(mid, malformed);
+ dequeue_mid(server, mid, malformed);
mid->resp_buf = server->smallbuf;
server->smallbuf = NULL;
return length;
@@ -1697,7 +1161,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
unsigned int data_offset, data_len;
struct cifs_io_subrequest *rdata = mid->callback_data;
char *buf = server->smallbuf;
- unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
+ unsigned int buflen = server->pdu_size;
bool use_rdma_mr = false;
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%zu\n",
@@ -1731,14 +1195,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
/* set up first two iov for signature check and to get credits */
rdata->iov[0].iov_base = buf;
- rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
- rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
- rdata->iov[1].iov_len =
- server->total_read - HEADER_PREAMBLE_SIZE(server);
+ rdata->iov[0].iov_len = server->total_read;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
- cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
- rdata->iov[1].iov_base, rdata->iov[1].iov_len);
/* Was the SMB read successful? */
rdata->result = server->ops->map_error(buf, false);
@@ -1754,12 +1213,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
__func__, server->total_read,
server->vals->read_rsp_size);
- rdata->result = -EIO;
+ rdata->result = smb_EIO2(smb_eio_trace_read_rsp_short,
+ server->total_read, server->vals->read_rsp_size);
return cifs_readv_discard(server, mid);
}
- data_offset = server->ops->read_data_offset(buf) +
- HEADER_PREAMBLE_SIZE(server);
+ data_offset = server->ops->read_data_offset(buf);
if (data_offset < server->total_read) {
/*
* win2k8 sometimes sends an offset of 0 when the read
@@ -1773,7 +1232,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
/* data_offset is beyond the end of smallbuf */
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
__func__, data_offset);
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_read_overlarge,
+ data_offset);
return cifs_readv_discard(server, mid);
}
@@ -1788,6 +1248,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (length < 0)
return length;
server->total_read += length;
+ rdata->iov[0].iov_len = server->total_read;
}
/* how much data is in the response? */
@@ -1797,7 +1258,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
data_len = server->ops->read_data_length(buf, use_rdma_mr);
if (!use_rdma_mr && (data_offset + data_len > buflen)) {
/* data_len is corrupt -- discard frame */
- rdata->result = -EIO;
+ rdata->result = smb_EIO2(smb_eio_trace_read_rsp_malformed,
+ data_offset + data_len, buflen);
return cifs_readv_discard(server, mid);
}
@@ -1819,7 +1281,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (server->total_read < buflen)
return cifs_readv_discard(server, mid);
- dequeue_mid(mid, false);
+ dequeue_mid(server, mid, false);
mid->resp_buf = server->smallbuf;
server->smallbuf = NULL;
return length;
diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c
index b88fa04f5792..23227f2f9428 100644
--- a/fs/smb/client/xattr.c
+++ b/fs/smb/client/xattr.c
@@ -11,7 +11,6 @@
#include <linux/slab.h>
#include <linux/xattr.h>
#include "cifsfs.h"
-#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -150,7 +149,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
break;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
goto out;
if (pTcon->ses->server->ops->set_EA) {
@@ -178,7 +177,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
memcpy(pacl, value, size);
if (pTcon->ses->server->ops->set_acl) {
int aclflags = 0;
- rc = 0;
switch (handler->flags) {
case XATTR_CIFS_NTSD_FULL:
@@ -311,7 +309,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
break;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
goto out;
if (pTcon->ses->server->ops->query_all_EAs)
@@ -398,9 +396,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
void *page;
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return smb_EIO(smb_eio_trace_forced_shutdown);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
return -EOPNOTSUPP;
tlink = cifs_sb_tlink(cifs_sb);