fs/crypto/bio.c

Source file repositories/reference/linux-study-clean/fs/crypto/bio.c

File Facts

System
Linux kernel
Corpus path
fs/crypto/bio.c
Extension
.c
Size
6244 bytes
Lines
217
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration 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

struct fscrypt_zero_done {
	atomic_t		pending;
	blk_status_t		status;
	struct completion	done;
};

static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
{
	if (atomic_dec_and_test(&done->pending))
		complete(&done->done);
}

static void fscrypt_zeroout_range_end_io(struct bio *bio)
{
	struct fscrypt_zero_done *done = bio->bi_private;

	if (bio->bi_status)
		cmpxchg(&done->status, 0, bio->bi_status);
	fscrypt_zeroout_range_done(done);
	bio_put(bio);
}

static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
					      loff_t pos, sector_t sector,
					      u64 len)
{
	struct fscrypt_zero_done done = {
		.pending	= ATOMIC_INIT(1),
		.done		= COMPLETION_INITIALIZER_ONSTACK(done.done),
	};

	while (len) {
		struct bio *bio;
		unsigned int n;

		bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
				GFP_NOFS);
		bio->bi_iter.bi_sector = sector;
		bio->bi_private = &done;
		bio->bi_end_io = fscrypt_zeroout_range_end_io;
		fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);

		for (n = 0; n < BIO_MAX_VECS; n++) {
			unsigned int bytes_this_page = min(len, PAGE_SIZE);

			__bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
			len -= bytes_this_page;
			pos += bytes_this_page;
			sector += (bytes_this_page >> SECTOR_SHIFT);
			if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
				break;
		}

		atomic_inc(&done.pending);
		blk_crypto_submit_bio(bio);
	}

	fscrypt_zeroout_range_done(&done);

	wait_for_completion(&done.done);
	return blk_status_to_errno(done.status);
}

/**
 * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
 * @inode: the file's inode
 * @pos: the first file position (in bytes) to zero out
 * @sector: the first sector to zero out
 * @len: bytes to zero out
 *
 * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
 * ciphertext blocks which decrypt to the all-zeroes block.  The blocks must be
 * both logically and physically contiguous.  It's also assumed that the
 * filesystem only uses a single block device, ->s_bdev.  @len must be a
 * multiple of the file system logical block size.
 *
 * Note that since each block uses a different IV, this involves writing a
 * different ciphertext to each block; we can't simply reuse the same one.
 *
 * Return: 0 on success; -errno on failure.
 */
int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
			  sector_t sector, u64 len)
{
	const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
	const unsigned int du_bits = ci->ci_data_unit_bits;
	const unsigned int du_size = 1U << du_bits;
	const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits;
	const unsigned int du_per_page = 1U << du_per_page_bits;
	u64 du_index = pos >> du_bits;

Annotation

Implementation Notes