fs/smb/server/compress.c

Source file repositories/reference/linux-study-clean/fs/smb/server/compress.c

File Facts

System
Linux kernel
Corpus path
fs/smb/server/compress.c
Extension
.c
Size
6046 bytes
Lines
210
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (work->iov[i].iov_len > src + src_len - p) {
			rc = -EINVAL;
			goto out;
		}
		memcpy(p, work->iov[i].iov_base, work->iov[i].iov_len);
		p += work->iov[i].iov_len;
	}
	if (p != src + src_len) {
		rc = -EINVAL;
		goto out;
	}

	max_dst_len = smb_lz77_compressed_alloc_size(src_len) +
		sizeof(struct smb2_compression_hdr) +
		3 * sizeof(struct smb2_compression_payload_hdr) +
		2 * sizeof(struct smb2_compression_pattern_v1);
	out = kvzalloc(sizeof(__be32) + max_dst_len,
		       KSMBD_DEFAULT_GFP);
	if (!out) {
		rc = -ENOMEM;
		goto out;
	}

	if (work->conn->compress_chained) {
		dst_len = max_dst_len;
		rc = smb_compression_compress_chained(SMB3_COMPRESS_LZ77,
						      work->conn->compress_pattern,
						      src, src_len,
						      out + sizeof(__be32),
						      &dst_len);
		if (rc == -EMSGSIZE || dst_len >= src_len) {
			rc = 0;
			goto out;
		}
		if (rc)
			goto out;
		compressed_pdu_len = dst_len;
	} else {
		/*
		 * Peers which did not negotiate chained compression still use
		 * the original 16-byte unchained transform format.
		 */
		dst_len = smb_lz77_compressed_alloc_size(src_len);
		rc = smb_lz77_compress(src, src_len,
				       out + sizeof(__be32) + sizeof(*chdr),
				       &dst_len);
		if (rc == -EMSGSIZE ||
		    dst_len + sizeof(*chdr) >= src_len) {
			rc = 0;
			goto out;
		}
		if (rc)
			goto out;

		compressed_pdu_len = sizeof(*chdr) + dst_len;
		chdr = (struct smb2_compression_hdr *)(out + sizeof(__be32));
		chdr->ProtocolId = SMB2_COMPRESSION_TRANSFORM_ID;
		chdr->OriginalCompressedSegmentSize = cpu_to_le32(src_len);
		chdr->CompressionAlgorithm = SMB3_COMPRESS_LZ77;
		chdr->Flags = cpu_to_le16(SMB2_COMPRESSION_FLAG_NONE);
		chdr->Offset = 0;
	}

	*(__be32 *)out = cpu_to_be32(compressed_pdu_len);

	/*
	 * Keep the transform in work->compress_buf until send completion.
	 * Existing response iovs can then be replaced without changing their
	 * individual ownership rules.
	 */
	work->compress_buf = out;
	work->iov[0].iov_base = out;
	work->iov[0].iov_len = sizeof(__be32);
	work->iov[1].iov_base = out + sizeof(__be32);
	work->iov[1].iov_len = compressed_pdu_len;
	work->iov_cnt = 2;
	work->iov_idx = 1;
	out = NULL;
	rc = 1;
out:
	kvfree(out);
	kvfree(src);
	return rc;
}

Annotation

Implementation Notes