From: Christopher Hoffman Date: Mon, 20 Oct 2025 18:15:11 +0000 (+0000) Subject: client: Use nearest fscrypt block when clamping max io size X-Git-Tag: testing/wip-vshankar-testing-20260120.085915-debug^2~13^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ae65b1b3e35c75608348a55b2bfa9d57c691d964;p=ceph-ci.git client: Use nearest fscrypt block when clamping max io size A max io size can currently be up to INT_MAX. If it is greater, then clamp the size to INT_MAX. This conflicts with fscrypt io operations. An fscrypt, op needs to read a whole fscrypt block. The size of fscrypt block size is 4K, INT_MAX % 4K is not equal to 0. Therefore, get the nearest multiple of 4K to INT_MAX that does not go over. In the fscrypt case, this value will be used for clamping max io size. Fixes: https://tracker.ceph.com/issues/73346 Signed-off-by: Christopher Hoffman --- diff --git a/src/client/Client.cc b/src/client/Client.cc index de3626862a4..d865dd7c4f6 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -11315,8 +11315,18 @@ int Client::read(int fd, char *buf, loff_t size, loff_t offset) return -EBADF; #endif bufferlist bl; - /* We can't return bytes written larger than INT_MAX, clamp size to that */ +#if defined(__linux__) + /* We can't return bytes written larger than INT_MAX, clamp size to + * that or FSCRYPT_MAXIO_SIZE*/ + Inode *in = f->inode.get(); + if (in->is_fscrypt_enabled()) { + size = std::min(size, (loff_t)FSCRYPT_MAXIO_SIZE); + } else { + size = std::min(size, (loff_t)INT_MAX); + } +#else size = std::min(size, (loff_t)INT_MAX); +#endif int r = _read(f, offset, size, &bl); ldout(cct, 3) << "read(" << fd << ", " << (void*)buf << ", " << size << ", " << offset << ") = " << r << dendl; if (r >= 0) { @@ -12017,8 +12027,18 @@ int Client::write(int fd, const char *buf, loff_t size, loff_t offset) if (fh->flags & O_PATH) return -EBADF; #endif - /* We can't return bytes written larger than INT_MAX, clamp size to that */ +#if defined(__linux__) + /* We can't return bytes written larger than INT_MAX, clamp size to + * that or FSCRYPT_MAXIO_SIZE*/ + Inode *in = fh->inode.get(); + if (in->is_fscrypt_enabled()) { + size = std::min(size, (loff_t)FSCRYPT_MAXIO_SIZE); + } else { + size = std::min(size, (loff_t)INT_MAX); + } +#else size = std::min(size, (loff_t)INT_MAX); +#endif bufferlist bl; bl.append(buf, size); int r = _write(fh, offset, size, std::move(bl)); @@ -12058,7 +12078,18 @@ int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov, */ bufferlist data; if (clamp_to_int) { +#if defined(__linux__) + /* We can't return bytes written larger than INT_MAX, clamp size to + * that or FSCRYPT_MAXIO_SIZE*/ + Inode *in = fh->inode.get(); + if (in->is_fscrypt_enabled()) { + totallen = std::min(totallen, (size_t)FSCRYPT_MAXIO_SIZE); + } else { + totallen = std::min(totallen, (size_t)INT_MAX); + } +#else totallen = std::min(totallen, (size_t)INT_MAX); +#endif size_t total_appended = 0; for (int i = 0; i < iovcnt; i++) { if (iov[i].iov_len > 0) { @@ -16979,9 +17010,19 @@ int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl) return -ENOTCONN; } +#if defined(__linux__) + /* We can't return bytes written larger than INT_MAX, clamp size to + * that or FSCRYPT_MAXIO_SIZE*/ + Inode *in = fh->inode.get(); + if (in->is_fscrypt_enabled()) { + len = std::min(len, (loff_t)FSCRYPT_MAXIO_SIZE); + } else { /* We can't return bytes written larger than INT_MAX, clamp len to that */ + len = std::min(len, (loff_t)INT_MAX); + } +#else len = std::min(len, (loff_t)INT_MAX); - +#endif std::scoped_lock lock(client_lock); if (fh == NULL || !_ll_fh_exists(fh)) { ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl; @@ -17124,9 +17165,18 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data) return -ENOTCONN; } - /* We can't return bytes written larger than INT_MAX, clamp len to that */ +#if defined(__linux__) + /* We can't return bytes written larger than INT_MAX, clamp size to + * that or FSCRYPT_MAXIO_SIZE*/ + Inode *in = fh->inode.get(); + if (in->is_fscrypt_enabled()) { + len = std::min(len, (loff_t)FSCRYPT_MAXIO_SIZE); + } else { + len = std::min(len, (loff_t)INT_MAX); + } +#else len = std::min(len, (loff_t)INT_MAX); - +#endif std::scoped_lock lock(client_lock); if (fh == NULL || !_ll_fh_exists(fh)) { ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl; diff --git a/src/client/FSCrypt.h b/src/client/FSCrypt.h index 30b5a0300a3..97baee7fdb5 100644 --- a/src/client/FSCrypt.h +++ b/src/client/FSCrypt.h @@ -21,6 +21,10 @@ #define FSCRYPT_DATA_ALIGNMENT 16 +// fscrypt maxio_size cannot be INT_MAX as it is not a multiple of fscrypt +// block size. Set it to nearest fscrypt block without exceeding INT_MAX +#define FSCRYPT_MAXIO_SIZE fscrypt_block_start(INT_MAX) + static inline uint64_t fscrypt_align_ofs(uint64_t ofs) { return (ofs + FSCRYPT_DATA_ALIGNMENT - 1) & ~(FSCRYPT_DATA_ALIGNMENT - 1); }