Linux CIFS filesystem development
 help / color / mirror / Atom feed
From: Namjae Jeon <linkinjeon@kernel.org>
To: linux-cifs@vger.kernel.org
Cc: senozhatsky@chromium.org, tom@talpey.com,
	atteh.mailbox@gmail.com, chenxiaosong@chenxiaosong.com,
	chenxiaosong@kylinos.cn, Namjae Jeon <linkinjeon@kernel.org>
Subject: [PATCH 11/22] ksmbd: support SMB2 quota query and set information
Date: Sat, 17 Oct 2026 10:03:33 +0900	[thread overview]
Message-ID: <20261017010344.11478-11-linkinjeon@kernel.org> (raw)
In-Reply-To: <20261017010344.11478-1-linkinjeon@kernel.org>

Handle SMB2_0_INFO_QUOTA in QUERY_INFO and SET_INFO using the user
quota operations on the volume containing the open. Validate the
request buffers and linked SID entries before accessing quota data.

Enumerate quotas with a per-open cursor, apply restart and single-entry
requests, and return aligned FILE_QUOTA_INFORMATION records. Return
zeroed records for SIDs without a quota entry and report buffer and
end-of-list statuses required by SMB2.

Allow the root session user to update quota limits. Reject deletion
and explicit zero-byte limits because Linux user quotas cannot
represent those values without changing their meaning.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
---
 fs/smb/server/smb2pdu.c   | 423 ++++++++++++++++++++++++++++++++++++++
 fs/smb/server/smb2pdu.h   |  26 +++
 fs/smb/server/vfs_cache.c |   1 +
 fs/smb/server/vfs_cache.h |   2 +
 4 files changed, 452 insertions(+)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 9d6426450827..856648d93f6e 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -19,6 +19,7 @@
 #include <linux/math.h>
 #include <linux/timekeeping.h>
 #include <linux/unaligned.h>
+#include <linux/quota.h>
 
 #include "glob.h"
 #include "../common/smbfsctl.h"
@@ -8064,6 +8065,342 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
 	return rc;
 }
 
+static unsigned int smb2_current_req_len(struct ksmbd_work *work,
+					 struct smb2_hdr *hdr);
+
+static int smb2_quota_sid_len(const u8 *buf, u32 len)
+{
+	const struct smb_sid *sid = (const struct smb_sid *)buf;
+	u32 size;
+
+	if (len < CIFS_SID_BASE_SIZE || sid->revision != 1 ||
+	    sid->num_subauth > SID_MAX_SUB_AUTHORITIES)
+		return -EINVAL;
+	size = CIFS_SID_BASE_SIZE + sid->num_subauth * sizeof(__le32);
+	return size <= len ? size : -EINVAL;
+}
+
+/* Linux user quotas can name local users through the server or Unix SID. */
+static int smb2_quota_sid_to_uid(const u8 *buf, u32 len, u32 *uid)
+{
+	const struct smb_sid *sid = (const struct smb_sid *)buf;
+	struct smb_sid expected;
+	u32 id;
+
+	if (smb2_quota_sid_len(buf, len) != len || !sid->num_subauth)
+		return -EINVAL;
+	id = le32_to_cpu(sid->sub_auth[sid->num_subauth - 1]);
+	if (server_conf.domain_sid.num_subauth < SID_MAX_SUB_AUTHORITIES) {
+		id_to_sid(id, SIDOWNER, &expected);
+		if (expected.num_subauth == sid->num_subauth &&
+		    !memcmp(&expected, sid, len)) {
+			*uid = id;
+			return 0;
+		}
+	}
+	id_to_sid(id, SIDUNIX_USER, &expected);
+	if (expected.num_subauth == sid->num_subauth &&
+	    !memcmp(&expected, sid, len)) {
+		*uid = id;
+		return 0;
+	}
+	return -ENOENT;
+}
+
+static int smb2_quota_check_list(const u8 *buf, u32 len, bool set)
+{
+	u32 pos = 0, base = set ? sizeof(struct smb2_file_quota_info) :
+				  sizeof(struct smb2_get_quota_info);
+	u32 align = set ? 8 : 4;
+
+	if (!len)
+		return -EINVAL;
+	while (pos < len) {
+		u32 next;
+		u32 sid_len;
+
+		if (len - pos < base)
+			return -EINVAL;
+		next = get_unaligned_le32(buf + pos);
+		sid_len = get_unaligned_le32(buf + pos + sizeof(__le32));
+		if (sid_len > len - pos - base ||
+		    smb2_quota_sid_len(buf + pos + base, sid_len) != sid_len)
+			return -EINVAL;
+		if (!next)
+			return len - pos - base - sid_len < align ? 0 : -EINVAL;
+		if (next < ALIGN(base + sid_len, align) || next > len - pos ||
+		    !IS_ALIGNED(next, align))
+			return -EINVAL;
+		pos += next;
+	}
+	return -EINVAL;
+}
+
+static void smb2_quota_set_status(struct smb2_hdr *hdr, int rc)
+{
+	switch (rc) {
+	case -EOPNOTSUPP:
+	case -ENOSYS:
+	case -ESRCH:
+		hdr->Status = STATUS_NOT_SUPPORTED;
+		break;
+	case -EACCES:
+	case -EPERM:
+		hdr->Status = STATUS_ACCESS_DENIED;
+		break;
+	case -ENOSPC:
+		hdr->Status = STATUS_BUFFER_TOO_SMALL;
+		break;
+	case -EINVAL:
+		hdr->Status = STATUS_INVALID_PARAMETER;
+		break;
+	case -ENOMEM:
+		hdr->Status = STATUS_INSUFFICIENT_RESOURCES;
+		break;
+	case -EDQUOT:
+		hdr->Status = STATUS_QUOTA_EXCEEDED;
+		break;
+	case -EROFS:
+		hdr->Status = STATUS_MEDIA_WRITE_PROTECTED;
+		break;
+	default:
+		hdr->Status = STATUS_UNEXPECTED_IO_ERROR;
+	}
+}
+
+static int smb2_quota_append(struct smb2_query_info_rsp *rsp, u32 max_len,
+			     u32 *used, struct smb2_file_quota_info **last,
+			     const u8 *sid, u32 sid_len,
+			     const struct qc_dqblk *dq)
+{
+	struct smb2_file_quota_info *entry;
+	u32 pos = *used;
+
+	if (*last)
+		pos = ALIGN(pos, 8);
+	if (pos > max_len || sid_len > max_len - pos ||
+	    sizeof(*entry) > max_len - pos - sid_len)
+		return -ENOSPC;
+	if (*last) {
+		(*last)->NextEntryOffset = cpu_to_le32(pos -
+			((u8 *)*last - rsp->Buffer));
+		memset(rsp->Buffer + *used, 0, pos - *used);
+	}
+	entry = (struct smb2_file_quota_info *)(rsp->Buffer + pos);
+	memset(entry, 0, sizeof(*entry));
+	entry->SidLength = cpu_to_le32(sid_len);
+	if (dq) {
+		entry->QuotaUsed = cpu_to_le64(dq->d_space);
+		entry->QuotaThreshold = cpu_to_le64(dq->d_spc_softlimit ?
+						 dq->d_spc_softlimit : U64_MAX);
+		entry->QuotaLimit = cpu_to_le64(dq->d_spc_hardlimit ?
+						 dq->d_spc_hardlimit : U64_MAX);
+	}
+	memcpy(entry->Sid, sid, sid_len);
+	*used = pos + sizeof(*entry) + sid_len;
+	*last = entry;
+	return 0;
+}
+
+static int smb2_get_info_quota(struct ksmbd_work *work,
+			       struct smb2_query_info_req *req,
+			       struct smb2_query_info_rsp *rsp)
+{
+	struct ksmbd_file *fp;
+	struct smb2_query_quota_info *query;
+	struct smb2_file_quota_info *last = NULL;
+	struct super_block *sb;
+	struct qc_dqblk dq;
+	struct smb_sid sid;
+	struct kqid qid;
+	const u8 *list;
+	u32 in_len = le32_to_cpu(req->InputBufferLength);
+	u32 list_len, start_len, start_off, used = 0, pos = 0, next_id = 0;
+	u32 uid, sid_len, entry_len;
+	u32 sid_type;
+	int max_len, rc = 0;
+	bool explicit_list, scan;
+
+	if (in_len < sizeof(*query) ||
+	    le16_to_cpu(req->InputBufferOffset) < offsetof(typeof(*req), Buffer) ||
+	    le16_to_cpu(req->InputBufferOffset) >
+			smb2_current_req_len(work, &req->hdr) ||
+	    in_len > smb2_current_req_len(work, &req->hdr) -
+			le16_to_cpu(req->InputBufferOffset)) {
+		rc = -EINVAL;
+		goto out_status;
+	}
+	query = (void *)req + le16_to_cpu(req->InputBufferOffset);
+	list_len = le32_to_cpu(query->SidListLength);
+	start_len = le32_to_cpu(query->StartSidLength);
+	start_off = le32_to_cpu(query->StartSidOffset);
+	if (list_len) {
+		if (list_len > in_len - sizeof(*query) ||
+		    smb2_quota_check_list(query->SidBuffer, list_len, false)) {
+			rc = -EINVAL;
+			goto out_status;
+		}
+	} else if (start_len || start_off) {
+		if (!start_len || start_off > in_len - sizeof(*query) ||
+		    start_len > in_len - sizeof(*query) - start_off ||
+		    smb2_quota_sid_len(query->SidBuffer + start_off,
+				   start_len) != start_len) {
+			rc = -EINVAL;
+			goto out_status;
+		}
+	}
+
+	max_len = smb2_calc_max_out_buf_len(work,
+			offsetof(struct smb2_query_info_rsp, Buffer),
+			le32_to_cpu(req->OutputBufferLength));
+	if (max_len < 0) {
+		rc = -EINVAL;
+		goto out_status;
+	}
+	if (!max_len) {
+		rc = -ENOSPC;
+		goto out_status;
+	}
+
+	if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS &&
+	    !has_file_id(req->VolatileFileId))
+		fp = ksmbd_lookup_fd_slow(work, work->compound_fid,
+					  work->compound_pfid);
+	else
+		fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId,
+					  req->PersistentFileId);
+	if (!fp) {
+		rc = -ENOENT;
+		rsp->hdr.Status = STATUS_FILE_CLOSED;
+		goto out_status;
+	}
+	sb = file_inode(fp->filp)->i_sb;
+	if (!sb->s_qcop || !sb->s_qcop->get_nextdqblk) {
+		rc = -EOPNOTSUPP;
+		goto out_fd;
+	}
+	explicit_list = list_len != 0;
+	scan = !explicit_list;
+	list = query->SidBuffer;
+	if (scan) {
+		sid_type = server_conf.domain_sid.num_subauth <
+			SID_MAX_SUB_AUTHORITIES ? SIDOWNER : SIDUNIX_USER;
+		id_to_sid(0, sid_type, &sid);
+		sid_len = CIFS_SID_BASE_SIZE + sid.num_subauth * sizeof(__le32);
+		if (max_len < sizeof(struct smb2_file_quota_info) + sid_len) {
+			rc = -ENOSPC;
+			goto out_fd;
+		}
+		if (start_len) {
+			rc = smb2_quota_sid_to_uid(query->SidBuffer + start_off,
+						 start_len, &uid);
+			if (rc == -ENOENT) {
+				rc = -EINVAL;
+				goto out_fd;
+			}
+			if (rc)
+				goto out_fd;
+			if (uid == U32_MAX)
+				goto no_more;
+			next_id = uid + 1;
+		} else {
+			mutex_lock(&fp->quota_lock);
+			if (query->RestartScan)
+				fp->current_quota_id = 0;
+			next_id = fp->current_quota_id;
+		}
+	}
+
+	while (true) {
+		if (explicit_list) {
+			const struct smb2_get_quota_info *item =
+				(const void *)(list + pos);
+			bool found = false;
+
+			sid_len = le32_to_cpu(item->SidLength);
+			rc = smb2_quota_sid_to_uid(item->Sid, sid_len, &uid);
+			if (rc == -EINVAL)
+				goto out_scan;
+			entry_len = sizeof(struct smb2_file_quota_info) + sid_len;
+			if (ALIGN(used, 8) + entry_len > max_len) {
+				rc = used ? 0 : -ENOSPC;
+				break;
+			}
+			if (!rc) {
+				qid = make_kqid(&init_user_ns, USRQUOTA, uid);
+				rc = sb->s_qcop->get_nextdqblk(sb, &qid, &dq);
+				if (rc == -ENOENT)
+					rc = 0;
+				else if (rc)
+					goto out_scan;
+				else
+					found = from_kqid(&init_user_ns, qid) == uid;
+			} else if (rc == -ENOENT) {
+				rc = 0;
+			}
+			rc = smb2_quota_append(rsp, max_len, &used, &last,
+						item->Sid, sid_len,
+						found ? &dq : NULL);
+			if (rc)
+				goto out_scan;
+			if (!item->NextEntryOffset || query->ReturnSingle)
+				break;
+			pos += le32_to_cpu(item->NextEntryOffset);
+		} else {
+			if (next_id == U32_MAX)
+				break;
+			if (ALIGN(used, 8) + sizeof(struct smb2_file_quota_info) +
+			    sid_len > max_len)
+				break;
+			qid = make_kqid(&init_user_ns, USRQUOTA, next_id);
+			rc = sb->s_qcop->get_nextdqblk(sb, &qid, &dq);
+			if (rc == -ENOENT) {
+				rc = 0;
+				break;
+			}
+			if (rc)
+				goto out_scan;
+			uid = from_kqid(&init_user_ns, qid);
+			if (uid < next_id) {
+				rc = -EIO;
+				goto out_scan;
+			}
+			id_to_sid(uid, sid_type, &sid);
+			rc = smb2_quota_append(rsp, max_len, &used, &last,
+						(const u8 *)&sid, sid_len, &dq);
+			if (rc)
+				goto out_scan;
+			next_id = uid == U32_MAX ? U32_MAX : uid + 1;
+			if (uid == U32_MAX || query->ReturnSingle)
+				break;
+		}
+	}
+out_scan:
+	if (scan && !start_len) {
+		if (!rc && used)
+			fp->current_quota_id = next_id;
+		mutex_unlock(&fp->quota_lock);
+	}
+	if (rc)
+		goto out_fd;
+no_more:
+	if (!used) {
+		rsp->hdr.Status = STATUS_NO_MORE_ENTRIES;
+		rsp->OutputBufferOffset = 0;
+		rsp->OutputBufferLength = 0;
+	} else {
+		rsp->OutputBufferLength = cpu_to_le32(used);
+	}
+	rc = ksmbd_iov_pin_rsp(work, rsp,
+			   offsetof(struct smb2_query_info_rsp, Buffer) + used);
+out_fd:
+	ksmbd_fd_put(work, fp);
+out_status:
+	if (rc && !rsp->hdr.Status)
+		smb2_quota_set_status(&rsp->hdr, rc);
+	return rc;
+}
+
 /**
  * smb2_query_info() - handler for smb2 query info command
  * @work:	smb work containing query info request buffer
@@ -8104,6 +8441,9 @@ int smb2_query_info(struct ksmbd_work *work)
 		ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");
 		rc = smb2_get_info_sec(work, req, rsp);
 		break;
+	case SMB2_O_INFO_QUOTA:
+		rc = smb2_get_info_quota(work, req, rsp);
+		break;
 	default:
 		ksmbd_debug(SMB, "InfoType %d not supported yet\n",
 			    req->InfoType);
@@ -8896,6 +9236,80 @@ static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info,
 			buf_len, false, true);
 }
 
+static int smb2_set_info_quota(struct ksmbd_work *work, struct ksmbd_file *fp,
+			       struct smb2_set_info_req *req)
+{
+	struct super_block *sb = file_inode(fp->filp)->i_sb;
+	const u8 *buf;
+	u32 len = le32_to_cpu(req->BufferLength);
+	u32 pos = 0, uid, next;
+	int rc;
+
+	if (!sb->s_qcop || !sb->s_qcop->set_dqblk)
+		return -EOPNOTSUPP;
+	/* The SMB session must have the volume's quota administrator right. */
+	if (user_uid(work->sess->user) != 0)
+		return -EACCES;
+	if (le16_to_cpu(req->BufferOffset) < offsetof(typeof(*req), Buffer) ||
+	    le16_to_cpu(req->BufferOffset) >
+			smb2_current_req_len(work, &req->hdr) ||
+	    len > smb2_current_req_len(work, &req->hdr) -
+			le16_to_cpu(req->BufferOffset))
+		return -EINVAL;
+	buf = (const u8 *)req + le16_to_cpu(req->BufferOffset);
+	rc = smb2_quota_check_list(buf, len, true);
+	if (rc)
+		return rc;
+
+	/* Validate the whole list before applying any of its entries. */
+	while (true) {
+		const struct smb2_file_quota_info *item =
+			(const void *)(buf + pos);
+		s64 soft = (s64)le64_to_cpu(item->QuotaThreshold);
+		s64 hard = (s64)le64_to_cpu(item->QuotaLimit);
+
+		rc = smb2_quota_sid_to_uid(item->Sid,
+					le32_to_cpu(item->SidLength), &uid);
+		if (rc)
+			return rc == -ENOENT ? -EOPNOTSUPP : rc;
+		/* Linux quotas have no delete operation or explicit zero limit. */
+		if (soft < -1 || hard < -1 || !soft || !hard)
+			return -EOPNOTSUPP;
+		next = le32_to_cpu(item->NextEntryOffset);
+		if (!next)
+			break;
+		pos += next;
+	}
+
+	pos = 0;
+	while (true) {
+		const struct smb2_file_quota_info *item =
+			(const void *)(buf + pos);
+		struct qc_dqblk dq = {
+			.d_fieldmask = QC_SPC_SOFT | QC_SPC_HARD,
+		};
+		struct kqid qid;
+		s64 soft = (s64)le64_to_cpu(item->QuotaThreshold);
+		s64 hard = (s64)le64_to_cpu(item->QuotaLimit);
+
+		rc = smb2_quota_sid_to_uid(item->Sid,
+					le32_to_cpu(item->SidLength), &uid);
+		if (rc)
+			return rc == -ENOENT ? -EOPNOTSUPP : rc;
+		qid = make_kqid(&init_user_ns, USRQUOTA, uid);
+		dq.d_spc_softlimit = soft == -1 ? 0 : soft;
+		dq.d_spc_hardlimit = hard == -1 ? 0 : hard;
+		rc = sb->s_qcop->set_dqblk(sb, qid, &dq);
+		if (rc)
+			return rc;
+		next = le32_to_cpu(item->NextEntryOffset);
+		if (!next)
+			break;
+		pos += next;
+	}
+	return 0;
+}
+
 /**
  * smb2_set_info() - handler for smb2 set info command handler
  * @work:	smb work containing set info request buffer
@@ -8969,6 +9383,9 @@ int smb2_set_info(struct ksmbd_work *work)
 				       (char *)req + le16_to_cpu(req->BufferOffset),
 				       le32_to_cpu(req->BufferLength));
 		break;
+	case SMB2_O_INFO_QUOTA:
+		rc = smb2_set_info_quota(work, fp, req);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
@@ -9012,6 +9429,12 @@ int smb2_set_info(struct ksmbd_work *work)
 		rsp->hdr.Status = STATUS_INVALID_HANDLE;
 	else if (rc == -EEXIST)
 		rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;
+	else if (req->InfoType == SMB2_O_INFO_QUOTA && !rsp->hdr.Status) {
+		if (rc == -ENOSPC)
+			rsp->hdr.Status = STATUS_DISK_FULL;
+		else
+			smb2_quota_set_status(&rsp->hdr, rc);
+	}
 	else if (rsp->hdr.Status == 0 || rc == -EOPNOTSUPP)
 		rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
 	smb2_set_err_rsp(work);
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
index c90a1d4e9f11..e07700d0a405 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -225,6 +225,32 @@ struct file_sparse {
 #define FILE_NETWORK_OPEN_INFORMATION_SIZE    56
 #define FILE_ATTRIBUTE_TAG_INFORMATION_SIZE   8
 
+struct smb2_query_quota_info {
+	u8 ReturnSingle;
+	u8 RestartScan;
+	__le16 Reserved;
+	__le32 SidListLength;
+	__le32 StartSidLength;
+	__le32 StartSidOffset;
+	u8 SidBuffer[];
+} __packed;
+
+struct smb2_get_quota_info {
+	__le32 NextEntryOffset;
+	__le32 SidLength;
+	u8 Sid[];
+} __packed;
+
+struct smb2_file_quota_info {
+	__le32 NextEntryOffset;
+	__le32 SidLength;
+	__le64 ChangeTime;
+	__le64 QuotaUsed;
+	__le64 QuotaThreshold;
+	__le64 QuotaLimit;
+	u8 Sid[];
+} __packed;
+
 /* FS Info response  size */
 #define FS_DEVICE_INFORMATION_SIZE     8
 #define FS_ATTRIBUTE_INFORMATION_SIZE  16
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index d63fed289c79..85f583189437 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -1491,6 +1491,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
 	INIT_LIST_HEAD(&fp->lock_list);
 	spin_lock_init(&fp->f_lock);
 	mutex_init(&fp->readdir_lock);
+	mutex_init(&fp->quota_lock);
 	atomic_set(&fp->refcount, 1);
 
 	fp->filp		= filp;
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 9de41b6e28ba..1054002ec4c5 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -157,6 +157,8 @@ struct ksmbd_file {
 	/* if ls is happening on directory, below is valid*/
 	struct ksmbd_readdir_data	readdir_data;
 	struct mutex			readdir_lock;
+	struct mutex			quota_lock;
+	u32				current_quota_id;
 	int				dot_dotdot[2];
 	unsigned int			f_state;
 	bool				reserve_lease_break;
-- 
2.25.1


  parent reply	other threads:[~2026-10-17  1:04 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17  1:03 [PATCH 01/22] ksmbd: release connection lock while draining old session Namjae Jeon
2026-10-17  1:03 ` [PATCH 02/22] ksmbd: serialize oplock break ACK state updates Namjae Jeon
2026-10-17  1:03 ` [PATCH 03/22] ksmbd: track delivery of queued TCP writes Namjae Jeon
2026-10-17  1:03 ` [PATCH 04/22] ksmbd: retry break notifications on another connection Namjae Jeon
2026-10-17  1:03 ` [PATCH 05/22] ksmbd: keep lease tables until their last lease is closed Namjae Jeon
2026-10-17  1:03 ` [PATCH 06/22] ksmbd: index byte-range locks independently of their connection Namjae Jeon
2026-10-17  1:03 ` [PATCH 07/22] ksmbd: rebind completed CREATE replays without draining the old channel Namjae Jeon
2026-10-17  1:03 ` [PATCH 08/22] ksmbd: track SMB2 locks above OFFSET_MAX in server lock table Namjae Jeon
2026-10-17  1:03 ` [PATCH 09/22] ksmbd: expire unacknowledged oplock breaks Namjae Jeon
2026-10-17  1:03 ` [PATCH 10/22] ksmbd: expire unacknowledged lease breaks Namjae Jeon
2026-10-17  1:03 ` Namjae Jeon [this message]
2026-10-17  1:03 ` [PATCH 12/22] ksmbd: validate POSIX negotiate contexts Namjae Jeon
2026-10-17  1:03 ` [PATCH 13/22] ksmbd: validate POSIX create contexts Namjae Jeon
2026-10-17  1:03 ` [PATCH 14/22] ksmbd: enforce POSIX append-only writes Namjae Jeon
2026-10-17  1:03 ` [PATCH 15/22] ksmbd: apply byte-range lock checks per open Namjae Jeon
2026-10-17  1:03 ` [PATCH 16/22] ksmbd: use requested mode in POSIX creates Namjae Jeon
2026-10-17  1:03 ` [PATCH 17/22] ksmbd: apply POSIX mode ACEs in security updates Namjae Jeon
2026-10-17  1:03 ` [PATCH 18/22] ksmbd: correct POSIX file metadata in responses Namjae Jeon
2026-10-17  1:03 ` [PATCH 19/22] ksmbd: include filenames in POSIX query info Namjae Jeon
2026-10-17  1:03 ` [PATCH 20/22] ksmbd: require POSIX opens for file and directory queries Namjae Jeon
2026-10-17  1:03 ` [PATCH 21/22] ksmbd: query POSIX filesystem info through the open file Namjae Jeon
2026-10-17  1:03 ` [PATCH 22/22] ksmbd: correct POSIX filesystem block size and response length Namjae Jeon

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20261017010344.11478-11-linkinjeon@kernel.org \
    --to=linkinjeon@kernel.org \
    --cc=atteh.mailbox@gmail.com \
    --cc=chenxiaosong@chenxiaosong.com \
    --cc=chenxiaosong@kylinos.cn \
    --cc=linux-cifs@vger.kernel.org \
    --cc=senozhatsky@chromium.org \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

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

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