1*7c478bd9Sstevel@tonic-gate /*- 2*7c478bd9Sstevel@tonic-gate * See the file LICENSE for redistribution information. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1996, 1997, 1998 5*7c478bd9Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*7c478bd9Sstevel@tonic-gate */ 7*7c478bd9Sstevel@tonic-gate #include "config.h" 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate #ifndef lint 10*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)mp_fput.c 10.24 (Sleepycat) 9/27/98"; 11*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 14*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <errno.h> 17*7c478bd9Sstevel@tonic-gate #endif 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate #include "db_int.h" 20*7c478bd9Sstevel@tonic-gate #include "shqueue.h" 21*7c478bd9Sstevel@tonic-gate #include "db_shash.h" 22*7c478bd9Sstevel@tonic-gate #include "mp.h" 23*7c478bd9Sstevel@tonic-gate #include "common_ext.h" 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* 26*7c478bd9Sstevel@tonic-gate * memp_fput -- 27*7c478bd9Sstevel@tonic-gate * Mpool file put function. 28*7c478bd9Sstevel@tonic-gate */ 29*7c478bd9Sstevel@tonic-gate int 30*7c478bd9Sstevel@tonic-gate memp_fput(dbmfp, pgaddr, flags) 31*7c478bd9Sstevel@tonic-gate DB_MPOOLFILE *dbmfp; 32*7c478bd9Sstevel@tonic-gate void *pgaddr; 33*7c478bd9Sstevel@tonic-gate u_int32_t flags; 34*7c478bd9Sstevel@tonic-gate { 35*7c478bd9Sstevel@tonic-gate BH *bhp; 36*7c478bd9Sstevel@tonic-gate DB_MPOOL *dbmp; 37*7c478bd9Sstevel@tonic-gate MPOOL *mp; 38*7c478bd9Sstevel@tonic-gate int wrote, ret; 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate dbmp = dbmfp->dbmp; 41*7c478bd9Sstevel@tonic-gate mp = dbmp->mp; 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate MP_PANIC_CHECK(dbmp); 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate /* Validate arguments. */ 46*7c478bd9Sstevel@tonic-gate if (flags) { 47*7c478bd9Sstevel@tonic-gate if ((ret = __db_fchk(dbmp->dbenv, "memp_fput", flags, 48*7c478bd9Sstevel@tonic-gate DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0) 49*7c478bd9Sstevel@tonic-gate return (ret); 50*7c478bd9Sstevel@tonic-gate if ((ret = __db_fcchk(dbmp->dbenv, "memp_fput", 51*7c478bd9Sstevel@tonic-gate flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0) 52*7c478bd9Sstevel@tonic-gate return (ret); 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) { 55*7c478bd9Sstevel@tonic-gate __db_err(dbmp->dbenv, 56*7c478bd9Sstevel@tonic-gate "%s: dirty flag set for readonly file page", 57*7c478bd9Sstevel@tonic-gate __memp_fn(dbmfp)); 58*7c478bd9Sstevel@tonic-gate return (EACCES); 59*7c478bd9Sstevel@tonic-gate } 60*7c478bd9Sstevel@tonic-gate } 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate LOCKREGION(dbmp); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* Decrement the pinned reference count. */ 65*7c478bd9Sstevel@tonic-gate if (dbmfp->pinref == 0) 66*7c478bd9Sstevel@tonic-gate __db_err(dbmp->dbenv, 67*7c478bd9Sstevel@tonic-gate "%s: put: more blocks returned than retrieved", 68*7c478bd9Sstevel@tonic-gate __memp_fn(dbmfp)); 69*7c478bd9Sstevel@tonic-gate else 70*7c478bd9Sstevel@tonic-gate --dbmfp->pinref; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * If we're mapping the file, there's nothing to do. Because we can 74*7c478bd9Sstevel@tonic-gate * stop mapping the file at any time, we have to check on each buffer 75*7c478bd9Sstevel@tonic-gate * to see if the address we gave the application was part of the map 76*7c478bd9Sstevel@tonic-gate * region. 77*7c478bd9Sstevel@tonic-gate */ 78*7c478bd9Sstevel@tonic-gate if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr && 79*7c478bd9Sstevel@tonic-gate (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len) { 80*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 81*7c478bd9Sstevel@tonic-gate return (0); 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate /* Convert the page address to a buffer header. */ 85*7c478bd9Sstevel@tonic-gate bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf)); 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* Set/clear the page bits. */ 88*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) { 89*7c478bd9Sstevel@tonic-gate ++mp->stat.st_page_clean; 90*7c478bd9Sstevel@tonic-gate --mp->stat.st_page_dirty; 91*7c478bd9Sstevel@tonic-gate F_CLR(bhp, BH_DIRTY); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) { 94*7c478bd9Sstevel@tonic-gate --mp->stat.st_page_clean; 95*7c478bd9Sstevel@tonic-gate ++mp->stat.st_page_dirty; 96*7c478bd9Sstevel@tonic-gate F_SET(bhp, BH_DIRTY); 97*7c478bd9Sstevel@tonic-gate } 98*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_MPOOL_DISCARD)) 99*7c478bd9Sstevel@tonic-gate F_SET(bhp, BH_DISCARD); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /* 102*7c478bd9Sstevel@tonic-gate * Check for a reference count going to zero. This can happen if the 103*7c478bd9Sstevel@tonic-gate * application returns a page twice. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate if (bhp->ref == 0) { 106*7c478bd9Sstevel@tonic-gate __db_err(dbmp->dbenv, "%s: page %lu: unpinned page returned", 107*7c478bd9Sstevel@tonic-gate __memp_fn(dbmfp), (u_long)bhp->pgno); 108*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 109*7c478bd9Sstevel@tonic-gate return (EINVAL); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * If more than one reference to the page, we're done. Ignore the 114*7c478bd9Sstevel@tonic-gate * discard flags (for now) and leave it at its position in the LRU 115*7c478bd9Sstevel@tonic-gate * chain. The rest gets done at last reference close. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate if (--bhp->ref > 0) { 118*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 119*7c478bd9Sstevel@tonic-gate return (0); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate /* Move the buffer to the head/tail of the LRU chain. */ 123*7c478bd9Sstevel@tonic-gate SH_TAILQ_REMOVE(&mp->bhq, bhp, q, __bh); 124*7c478bd9Sstevel@tonic-gate if (F_ISSET(bhp, BH_DISCARD)) 125*7c478bd9Sstevel@tonic-gate SH_TAILQ_INSERT_HEAD(&mp->bhq, bhp, q, __bh); 126*7c478bd9Sstevel@tonic-gate else 127*7c478bd9Sstevel@tonic-gate SH_TAILQ_INSERT_TAIL(&mp->bhq, bhp, q); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* 130*7c478bd9Sstevel@tonic-gate * If this buffer is scheduled for writing because of a checkpoint, we 131*7c478bd9Sstevel@tonic-gate * need to write it (if we marked it dirty), or update the checkpoint 132*7c478bd9Sstevel@tonic-gate * counters (if we didn't mark it dirty). If we try to write it and 133*7c478bd9Sstevel@tonic-gate * can't, that's not necessarily an error, but set a flag so that the 134*7c478bd9Sstevel@tonic-gate * next time the memp_sync function runs we try writing it there, as 135*7c478bd9Sstevel@tonic-gate * the checkpoint application better be able to write all of the files. 136*7c478bd9Sstevel@tonic-gate */ 137*7c478bd9Sstevel@tonic-gate if (F_ISSET(bhp, BH_WRITE)) 138*7c478bd9Sstevel@tonic-gate if (F_ISSET(bhp, BH_DIRTY)) { 139*7c478bd9Sstevel@tonic-gate if (__memp_bhwrite(dbmp, 140*7c478bd9Sstevel@tonic-gate dbmfp->mfp, bhp, NULL, &wrote) != 0 || !wrote) 141*7c478bd9Sstevel@tonic-gate F_SET(mp, MP_LSN_RETRY); 142*7c478bd9Sstevel@tonic-gate } else { 143*7c478bd9Sstevel@tonic-gate F_CLR(bhp, BH_WRITE); 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate --dbmfp->mfp->lsn_cnt; 146*7c478bd9Sstevel@tonic-gate --mp->lsn_cnt; 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 150*7c478bd9Sstevel@tonic-gate return (0); 151*7c478bd9Sstevel@tonic-gate } 152