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