From: Amos Jeffries Date: Sun, 19 Sep 2010 22:56:59 +0000 (+1200) Subject: Bug 3053: cache version 1 LFS support detection broken X-Git-Tag: take1~245 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=49991b926ed09df0cb7df3e8cfd87fc72a0f5797;p=thirdparty%2Fsquid.git Bug 3053: cache version 1 LFS support detection broken Alter the upgrade detection to only be used if needed, and to load the correct on-disk sizes for the fields being converted. Lock the sfileno type down to 32-bits. This also adds two new upgrade parsers: Fix 64-bit builds previously using sfileno as full 64-bit int Migrates swap.state from 32-bit to 64-bit time_t (old squid 2.4/2.5) 64-bit->32-bit system time_t migration remains broken. Per-file meta data is not altered by these changes, so problems may remain there. --- diff --git a/src/fs/ufs/ufscommon.cc b/src/fs/ufs/ufscommon.cc index 2723e07444..fcfbab3d7a 100644 --- a/src/fs/ufs/ufscommon.cc +++ b/src/fs/ufs/ufscommon.cc @@ -47,10 +47,14 @@ CBDATA_CLASS_INIT(RebuildState); - -class UFSSwapLogParser_old:public UFSSwapLogParser +/// Parse a swap header entry created on a system with 32-bit size_t and sfileno +/// this is typical of 32-bit systems without large file support +/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still. +class UFSSwapLogParser_v1_32bs:public UFSSwapLogParser { public: + /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz) + /// time_t an sfileno have no variation from the v1 baseline format struct StoreSwapLogDataOld { char op; sfileno swap_filen; @@ -58,41 +62,134 @@ public: time_t lastref; time_t expires; time_t lastmod; - size_t swap_file_sz; + uint32_t swap_file_sz; u_short refcount; u_short flags; unsigned char key[SQUID_MD5_DIGEST_LENGTH]; }; - UFSSwapLogParser_old(FILE *fp):UFSSwapLogParser(fp) { - record_size = sizeof(UFSSwapLogParser_old::StoreSwapLogDataOld); + UFSSwapLogParser_v1_32bs(FILE *fp):UFSSwapLogParser(fp) { + record_size = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld); } - bool ReadRecord(StoreSwapLogData &swapData); -}; + /// Convert the on-disk 32-bit format to our current format while reading + bool ReadRecord(StoreSwapLogData &swapData) { + UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld readData; + int bytes = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld); + + assert(log); + if (fread(&readData, bytes, 1, log) != 1) { + return false; + } + swapData.op = readData.op; + swapData.swap_filen = readData.swap_filen; + swapData.timestamp = readData.timestamp; + swapData.lastref = readData.lastref; + swapData.expires = readData.expires; + swapData.lastmod = readData.lastmod; + swapData.swap_file_sz = readData.swap_file_sz; + swapData.refcount = readData.refcount; + swapData.flags = readData.flags; + xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH); + return true; + } +}; -bool UFSSwapLogParser_old::ReadRecord(StoreSwapLogData &swapData) +/// Parse a swap header entry created on a system with 32-bit size_t, time_t and sfileno +/// this is typical of 32-bit systems without large file support and with old kernels +/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still. +class UFSSwapLogParser_v1_32bst:public UFSSwapLogParser { - UFSSwapLogParser_old::StoreSwapLogDataOld readData; - int bytes = sizeof(UFSSwapLogParser_old::StoreSwapLogDataOld); +public: + /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz) + /// time_t also differs + /// sfileno has no variation from the v1 baseline format + struct StoreSwapLogDataOld { + char op; + sfileno swap_filen; + int32_t timestamp; + int32_t lastref; + int32_t expires; + int32_t lastmod; + uint32_t swap_file_sz; + u_short refcount; + u_short flags; + unsigned char key[SQUID_MD5_DIGEST_LENGTH]; + }; + UFSSwapLogParser_v1_32bst(FILE *fp):UFSSwapLogParser(fp) { + record_size = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld); + } + /// Convert the on-disk 32-bit format to our current format while reading + bool ReadRecord(StoreSwapLogData &swapData) { + UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld readData; + int bytes = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld); - assert(log); + assert(log); - if (fread(&readData, bytes, 1, log) != 1) { - return false; + if (fread(&readData, bytes, 1, log) != 1) { + return false; + } + swapData.op = readData.op; + swapData.swap_filen = readData.swap_filen; + swapData.timestamp = readData.timestamp; + swapData.lastref = readData.lastref; + swapData.expires = readData.expires; + swapData.lastmod = readData.lastmod; + swapData.swap_file_sz = readData.swap_file_sz; + swapData.refcount = readData.refcount; + swapData.flags = readData.flags; + xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH); + return true; } - swapData.op = readData.op; - swapData.swap_filen = readData.swap_filen; - swapData.timestamp = readData.timestamp; - swapData.lastref = readData.lastref; - swapData.expires = readData.expires; - swapData.lastmod = readData.lastmod; - swapData.swap_file_sz = readData.swap_file_sz; - swapData.refcount = readData.refcount; - swapData.flags = readData.flags; - xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH); - return true; -} +}; + +/// Parse a swap header entry created on a system with 64-bit size_t and sfileno +/// this is typical of 64-bit systems prior to this patch fixing sfileno to 32-bits +/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still. +class UFSSwapLogParser_v1_64bfn:public UFSSwapLogParser +{ +public: + /// version 1 cache swap.state entry with 64-bit sfileno + struct StoreSwapLogDataOld { + char op; + int64_t swap_filen; + time_t timestamp; + time_t lastref; + time_t expires; + time_t lastmod; + uint64_t swap_file_sz; + u_short refcount; + u_short flags; + unsigned char key[SQUID_MD5_DIGEST_LENGTH]; + }; + UFSSwapLogParser_v1_64bfn(FILE *fp):UFSSwapLogParser(fp) { + record_size = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld); + } + /// Convert the on-disk 64-bit format to our current format while reading + bool ReadRecord(StoreSwapLogData &swapData) { + UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld readData; + int bytes = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld); + assert(log); + + if (fread(&readData, bytes, 1, log) != 1) { + return false; + } + swapData.op = readData.op; + if ((readData.swap_filen>>32) != 0) { + fatalf("File ID on record is greater than maximum cache file ID."); + } + swapData.swap_filen = (int32_t)readData.swap_filen; + swapData.timestamp = readData.timestamp; + swapData.lastref = readData.lastref; + swapData.expires = readData.expires; + swapData.lastmod = readData.lastmod; + swapData.swap_file_sz = readData.swap_file_sz; + swapData.refcount = readData.refcount; + swapData.flags = readData.flags; + xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH); + return true; + } +}; class UFSSwapLogParser_v1:public UFSSwapLogParser { @@ -127,29 +224,58 @@ UFSSwapLogParser *UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp) return NULL; if (header.op != SWAP_LOG_VERSION) { - debugs(47, 1, "Old swap file detected... "); + debugs(47, 1, "Old swap file detected..."); fseek(fp, 0, SEEK_SET); - return new UFSSwapLogParser_old(fp); + return new UFSSwapLogParser_v1_32bs(fp); // Um. 32-bits except time_t, and can't determine that. } if (header.version == 1) { if (fseek(fp, header.record_size, SEEK_SET) != 0) return NULL; - if (header.record_size == sizeof(struct UFSSwapLogParser_old::StoreSwapLogDataOld)) { - debugs(47, 1, "Version 1 of swap file without LFS support detected... "); - return new UFSSwapLogParser_old(fp); - } - + // baseline + // 32-bit sfileno + // native time_t (hopefully 64-bit) + // 64-bit file size if (header.record_size == sizeof(StoreSwapLogData)) { debugs(47, 1, "Version 1 of swap file with LFS support detected... "); return new UFSSwapLogParser_v1(fp); } - debugs(47, 1, "The swap file has wrong format!... "); + // which means we have a 3-way grid of permutations to import (yuck!) + // 1) sfileno 32-bit / 64-bit (64-bit was broken) + // 2) time_t 32-bit / 64-bit + // 3) size_t 32-bit / 64-bit (32-bit was pre-LFS) + + // 32-bit systems... + // only LFS (size_t) differs from baseline + if (header.record_size == sizeof(struct UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld)) { + debugs(47, 1, "Version 1 (32-bit) swap file without LFS support detected... "); + return new UFSSwapLogParser_v1_32bs(fp); + } + // LFS (size_t) and timestamps (time_t) differs from baseline + if (header.record_size == sizeof(struct UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld)) { + debugs(47, 1, "Version 1 (32-bit) swap file with short timestamps and without LFS support detected... "); + return new UFSSwapLogParser_v1_32bst(fp); + } + // No downgrade for 64-bit timestamps to 32-bit. + + // 64-bit systems + // sfileno was 64-bit for a some builds + if (header.record_size == sizeof(struct UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld)) { + debugs(47, 1, "Version 1 (64-bit) swap file with broken sfileno detected... "); + return new UFSSwapLogParser_v1_64bfn(fp); + } + // NP: 64-bit system with 32-bit size_t/time_t are not handled. + + debugs(47, 1, "WARNING: The swap file has wrong format!... "); + debugs(47, 1, "NOTE: Cannot safely downgrade caches to short (32-bit) timestamps."); return NULL; } + // XXX: version 2 of swapfile. This time use fixed-bit sizes for everything!! + // and preferrably write to disk in network-order bytes for the larger fields. + return NULL; } diff --git a/src/typedefs.h b/src/typedefs.h index 73034c75e7..b33594e4c7 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -36,7 +36,7 @@ #ifndef SQUID_TYPEDEFS_H #define SQUID_TYPEDEFS_H -typedef signed int sfileno; +typedef int32_t sfileno; typedef signed int sdirno; typedef struct {