/* * $Id: store_dir_ufs.c,v 1.7 2000/06/27 22:06:26 hno Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please see * the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "libufs.h" #if HAVE_STATVFS #if HAVE_SYS_STATVFS_H #include #endif #endif #define DefaultLevelOneDirs 16 #define DefaultLevelTwoDirs 256 #define STORE_META_BUFSZ 4096 /* Common routines between the UFS filesystems. Can be overridden, etc . */ char * libufs_StoreDirFullPath(SwapDir * SD, ufsinfo_t *ufsinfo, sfileno filn, char *fullpath) { LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); if (!fullpath) fullpath = fullfilename; fullpath[0] = '\0'; snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X", SD->path, ((filn / ufsinfo->l2) / ufsinfo->l2) % ufsinfo->l1, (filn / ufsinfo->l2) % ufsinfo->l2, filn); return fullpath; } int libufs_ValidFileno(SwapDir * SD, ufsinfo_t *ufsinfo, sfileno filn, int flag) { if (filn < 0) return 0; /* * If flag is set it means out-of-range file number should * be considered invalid. */ if (flag) if (filn > ufsinfo->map->max_n_files) return 0; return 1; } /* * These functions were ripped straight out of the heart of store_dir.c. * They assume that the given filenum is on a diskd partiton, which may or * may not be true.. * XXX this evilness should be tidied up at a later date! */ int libufs_DirMapBitTest(SwapDir * SD, ufsinfo_t *ufsinfo, int fn) { sfileno filn = fn; return file_map_bit_test(ufsinfo->map, filn); } void libufs_DirMapBitSet(SwapDir * SD, ufsinfo_t *ufsinfo, int fn) { sfileno filn = fn; file_map_bit_set(ufsinfo->map, filn); } void libufs_DirMapBitReset(SwapDir * SD, ufsinfo_t *ufsinfo, int fn) { sfileno filn = fn; file_map_bit_reset(ufsinfo->map, filn); } int libufs_DirMapBitAllocate(SwapDir * SD, ufsinfo_t *ufsinfo) { int fn; fn = file_map_allocate(ufsinfo->map, ufsinfo->suggest); file_map_bit_set(ufsinfo->map, fn); ufsinfo->suggest = fn + 1; return fn; } void libufs_FreeMemory(SwapDir *SD, ufsinfo_t *ufsinfo) { filemapFreeMemory(ufsinfo->map); } /* * Initialise the diskd bitmap * * If there already is a bitmap, and the numobjects is larger than currently * configured, we allocate a new bitmap and 'grow' the old one into it. */ void libufs_DirInitBitmap(SwapDir * sd, ufsinfo_t *ufsinfo) { if (ufsinfo->map == NULL) { /* First time */ ufsinfo->map = file_map_create(); } else if (ufsinfo->map->max_n_files) { /* it grew, need to expand */ /* XXX We don't need it anymore .. */ } /* else it shrunk, and we leave the old one in place */ } /* * Does swapfile number 'fn' belong in cachedir #F0, * level1 dir #F1, level2 dir #F2? */ int libufs_FilenoBelongsHere(ufsinfo_t *ufsinfo, int fn, int F0, int F1, int F2) { int D1, D2; int L1, L2; int filn = fn; assert(F0 < Config.cacheSwap.n_configured); L1 = ufsinfo->l1; L2 = ufsinfo->l2; D1 = ((filn / L2) / L2) % L1; if (F1 != D1) return 0; D2 = (filn / L2) % L2; if (F2 != D2) return 0; return 1; } /* * General UFS statistics * Call this *before* you tack your specific stuff on the end */ void libufs_DirStats(SwapDir * SD, ufsinfo_t *ufsinfo, StoreEntry * sentry) { #if HAVE_STATVFS struct statvfs sfs; #endif storeAppendPrintf(sentry, "First level subdirectories: %d\n", ufsinfo->l1) ; storeAppendPrintf(sentry, "Second level subdirectories: %d\n", ufsinfo->l2 ); storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", 100.0 * SD->cur_size / SD->max_size); storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", ufsinfo->map->n_files_in_map, ufsinfo->map->max_n_files, percent(ufsinfo->map->n_files_in_map, ufsinfo->map->max_n_files)); #if HAVE_STATVFS #define fsbtoblk(num, fsbs, bs) \ (((fsbs) != 0 && (fsbs) < (bs)) ? \ (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) if (!statvfs(SD->path, &sfs)) { storeAppendPrintf(sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n", fsbtoblk((sfs.f_blocks - sfs.f_bfree), sfs.f_frsize, 1024), fsbtoblk(sfs.f_blocks, sfs.f_frsize, 1024), percent(sfs.f_blocks - sfs.f_bfree, sfs.f_blocks)); storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n", sfs.f_files - sfs.f_ffree, sfs.f_files, percent(sfs.f_files - sfs.f_ffree, sfs.f_files)); } #endif storeAppendPrintf(sentry, "Flags:"); if (SD->flags.selected) storeAppendPrintf(sentry, " SELECTED"); if (SD->flags.read_only) storeAppendPrintf(sentry, " READ-ONLY"); storeAppendPrintf(sentry, "\n"); } char * libufs_SwapSubDir(SwapDir *sd, ufsinfo_t *ufsinfo, int subdirn) { LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); assert(0 <= subdirn && subdirn < ufsinfo->l1); snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", sd->path, subdirn); return fullfilename; } int libufs_VerifyDirectory(const char *path) { struct stat sb; if (stat(path, &sb) < 0) { debug(20, 0) ("%s: %s\n", path, xstrerror()); return -1; } if (S_ISDIR(sb.st_mode) == 0) { debug(20, 0) ("%s is not a directory\n", path); return -1; } return 0; } /* * This function is called by the fs init function. If this returns < 0, * then Squid exits, complains about swap directories not * existing, and instructs the admin to run 'squid -z' */ int libufs_VerifyCacheDirs(SwapDir *sd, ufsinfo_t *ufsinfo) { int j; const char *path = sd->path; if (libufs_VerifyDirectory(path) < 0) return -1; for (j = 0; j < ufsinfo->l1; j++) { path = libufs_SwapSubDir(sd, ufsinfo, j); if (libufs_VerifyDirectory(path) < 0) return -1; } return 0; } int libufs_CreateDirectory(const char *path, int should_exist) { int created = 0; struct stat st; getCurrentTime(); if (0 == stat(path, &st)) { if (S_ISDIR(st.st_mode)) { debug(20, should_exist ? 3 : 1) ("%s exists\n", path); } else { fatalf("Swap directory %s is not a directory.", path); } } else if (0 == mkdir(path, 0755)) { debug(20, should_exist ? 1 : 3) ("%s created\n", path); created = 1; } else { fatalf("Failed to make swap directory %s: %s", path, xstrerror()); } return created; } /* * Create the swapdirectories */ void libufs_CreateSwapSubDirs(SwapDir *sd, ufsinfo_t *ufsinfo) { int i, k; int should_exist; LOCAL_ARRAY(char, name, MAXPATHLEN); for (i = 0; i < ufsinfo->l1; i++) { snprintf(name, MAXPATHLEN, "%s/%02X", sd->path, i); if (libufs_CreateDirectory(name, 0)) should_exist = 0; else should_exist = 1; debug(47, 1) ("Making directories in %s\n", name); for (k = 0; k < ufsinfo->l2; k++) { snprintf(name, MAXPATHLEN, "%s/%02X/%02X", sd->path, i, k); libufs_CreateDirectory(name, should_exist); } } }