void sbdiskhash(Shabuf *sb, vlong eoffset) { static uchar dbuf[4*M]; int n; while(sb->offset < eoffset){ n = sizeof dbuf; if(sb->offset+n > eoffset) n = eoffset - sb->offset; readdisk(dbuf, sb->offset, n); sbupdate(sb, dbuf, sb->offset, n); } }
/* ARGSUSED2 */ static int lqfs_alloc(qfsvfs_t *qfsvfsp, struct fiolog *flp, cred_t *cr) { int error = 0; buf_t *bp = NULL; extent_t *ep, *nep; extent_block_t *ebp; fs_lqfs_common_t *fs = VFS_FS_PTR(qfsvfsp); daddr_t fno; /* in frags */ #ifdef LUFS daddr_t bno; /* in disk blocks */ #endif /* LUFS */ int32_t logbno = INT32_C(0); /* will be fs_logbno */ ushort_t logord = 0; /* will be fs_logord */ inode_t *ip = NULL; #ifndef LUFS sam_bn_t bno; #endif /* LUFS */ size_t nb = flp->nbytes_actual; size_t tb = 0; int ord = 0; uchar_t save_unit; /* * Mark the file system as FSACTIVE */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); LQFS_SET_FS_CLEAN(fs, FSACTIVE); #ifdef LUFS qfs_sbwrite(qfsvfsp); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); /* * Allocate the allocation block (need dummy shadow inode; * we use a shadow inode so the quota sub-system ignores * the block allocations.) * superblock -> one block of extents -> log data */ #ifdef LUFS ip = qfs_alloc_inode(qfsvfsp, QFSROOTINO); ip->i_mode = IFSHAD; /* make the dummy a shadow inode */ #else /* * Although QFS has "extension" inodes, it doesn't really implement * the concept of "shadow" inodes. We can't bypass having the quota * system track the allocation of log blocks. For now, use the * .inodes inode (SAM_INO_INO) to which we we will allocate space * for a UFS-like log of the requested size. Allocate space at mount * time BEFORE the quota system is initialized. */ ip = qfsvfsp->mi.m_inodir; #endif /* LUFS */ rw_enter(&ip->i_contents, RW_WRITER); #ifdef LUFS /* Allocate first log block (extent info). */ fno = contigpref(qfsvfsp, nb + FS_BSIZE(fs)); error = alloc(ip, fno, FS_BSIZE(fs), &fno, cr); #else save_unit = ip->di.unit; ip->di.unit = 0; if ((error = sam_alloc_block(ip, SM, &bno, &ord)) == 0) { /* Convert 4K block offset to 1K frag offset. */ fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { goto errout; } /* Convert 1K frag offset to 512B disk block offset. */ bno = fsbtodb(fs, fno); sam_bread_db(qfsvfsp, qfsvfsp->mi.m_fs[ord].dev, bno, FS_BSIZE(fs), &bp); if (bp->b_flags & B_ERROR) { error = EIO; goto errout; } ebp = (void *)bp->b_un.b_addr; ebp->type = LQFS_EXTENTS; ebp->nextbno = UINT32_C(0); ebp->nextord = 0; ebp->nextents = UINT32_C(0); ebp->chksum = INT32_C(0); #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { logbno = bno; } else { #endif /* LUFS */ logbno = dbtofsb(fs, bno); #ifdef LUFS } #endif /* LUFS */ logord = (ushort_t)ord; /* * Initialize the first extent */ ep = &ebp->extents[0]; #ifdef LUFS error = alloc(ip, fno + FS_FRAG(fs), FS_BSIZE(fs), &fno, cr); #else ip->di.unit = 0; if ((error = sam_alloc_block(ip, SM, &bno, &ord)) == 0) { /* Convert 4K block offset to 1K block (frag) offset. */ fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { goto errout; } /* Convert frag offset to physical disk block (512B block) offset. */ bno = fsbtodb(fs, fno); ep->lbno = UINT32_C(0); #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { ep->pbno = (uint32_t)bno; } else { #endif /* LUFS */ ep->pbno = (uint32_t)fno; #ifdef LUFS } #endif /* LUFS */ ep->nbno = (uint32_t)fsbtodb(fs, FS_FRAG(fs)); /* Has 8 disk blocks */ ep->ord = ord; ebp->nextents = UINT32_C(1); tb = FS_BSIZE(fs); nb -= FS_BSIZE(fs); while (nb) { #ifdef LUFS error = alloc(ip, fno + FS_FRAG(fs), FS_BSIZE(fs), &fno, cr); #else ip->di.unit = 0; error = sam_alloc_block(ip, SM, &bno, &ord); if (!error) { fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { if (tb < ldl_minlogsize) { goto errout; } error = 0; break; } bno = fsbtodb(fs, fno); if ((ep->ord == ord) && ((daddr_t)((logbtodb(fs, ep->pbno) + ep->nbno) == bno))) { ep->nbno += (uint32_t)(fsbtodb(fs, FS_FRAG(fs))); } else { nep = ep + 1; if ((caddr_t)(nep + 1) > (bp->b_un.b_addr + FS_BSIZE(fs))) { #ifdef LUFS free(ip, fno, FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, fno), ord); #endif /* LUFS */ break; } nep->lbno = ep->lbno + ep->nbno; #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { nep->pbno = (uint32_t)bno; } else { #endif /* LUFS */ nep->pbno = (uint32_t)fno; #ifdef LUFS } #endif /* LUFS */ nep->nbno = (uint32_t)(fsbtodb(fs, FS_FRAG(fs))); nep->ord = ord; ebp->nextents++; ep = nep; } tb += FS_BSIZE(fs); nb -= FS_BSIZE(fs); } ebp->nbytes = (uint32_t)tb; setsum(&ebp->chksum, (int32_t *)(void *)bp->b_un.b_addr, FS_BSIZE(fs)); if ((error = SAM_BWRITE2(qfsvfsp, bp)) != 0) { goto errout; } /* * Initialize the first two sectors of the log */ error = lqfs_initialize(qfsvfsp, logbtodb(fs, ebp->extents[0].pbno), ebp->extents[0].ord, tb, flp); if (error) { goto errout; } /* * We are done initializing the allocation block and the log */ brelse(bp); bp = NULL; /* * Update the superblock and push the dirty metadata */ UL_SBOWNER_SET(qfsvfsp, curthread); #ifdef LUFS sbupdate(qfsvfsp->vfs_vfs); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); #endif /* LUFS */ UL_SBOWNER_SET(qfsvfsp, -1); bflush(qfsvfsp->mi.m_fs[logord].dev); error = bfinval(qfsvfsp->mi.m_fs[logord].dev, 1); if (error) { goto errout; } #ifdef LUFS if (qfsvfsp->vfs_bufp->b_flags & B_ERROR) { error = EIO; goto errout; } #endif /* LUFS */ /* * Everything is safely on disk; update log space pointer in sb */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); LQFS_SET_LOGBNO(fs, (uint32_t)logbno); LQFS_SET_LOGORD(fs, logord); #ifdef LUFS qfs_sbwrite(qfsvfsp); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); ip->di.unit = save_unit; /* * Free the dummy inode */ rw_exit(&ip->i_contents); #ifdef LUFS qfs_free_inode(ip); #endif /* LUFS */ /* inform user of real log size */ flp->nbytes_actual = tb; return (0); errout: /* * Free all resources */ if (bp) { brelse(bp); } if (logbno) { LQFS_SET_LOGBNO(fs, logbno); LQFS_SET_LOGORD(fs, logord); (void) lqfs_free(qfsvfsp); } if (ip) { ip->di.unit = save_unit; rw_exit(&ip->i_contents); #ifdef LUFS qfs_free_inode(ip); #endif /* LUFS */ } return (error); }
/* * Free log space * Assumes the file system is write locked and is not logging */ int lqfs_free(qfsvfs_t *qfsvfsp) { int error = 0, i, j; buf_t *bp = NULL; extent_t *ep; extent_block_t *ebp; fs_lqfs_common_t *fs = VFS_FS_PTR(qfsvfsp); daddr_t fno; int32_t logbno; ushort_t logord; long nfno; inode_t *ip = NULL; char clean; /* * Nothing to free */ if (LQFS_GET_LOGBNO(fs) == 0) { return (0); } /* * Mark the file system as FSACTIVE and no log but honor the * current value of fs_reclaim. The reclaim thread could have * been active when lqfs_disable() was called and if fs_reclaim * is reset to zero here it could lead to lost inodes. */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); clean = LQFS_GET_FS_CLEAN(fs); logbno = LQFS_GET_LOGBNO(fs); logord = LQFS_GET_LOGORD(fs); LQFS_SET_FS_CLEAN(fs, FSACTIVE); LQFS_SET_LOGBNO(fs, INT32_C(0)); LQFS_SET_LOGORD(fs, 0); #ifdef LUFS qfs_sbwrite(qfsvfsp); error = (qfsvfsp->vfs_bufp->b_flags & B_ERROR); #else error = sam_update_sblk(qfsvfsp, 0, 0, TRUE); error = sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); if (error) { error = EIO; LQFS_SET_FS_CLEAN(fs, clean); LQFS_SET_LOGBNO(fs, logbno); LQFS_SET_LOGORD(fs, logord); goto errout; } /* * fetch the allocation block * superblock -> one block of extents -> log data */ sam_bread_db(qfsvfsp, qfsvfsp->mi.m_fs[logord].dev, logbtodb(fs, logbno), FS_BSIZE(fs), &bp); if (bp->b_flags & B_ERROR) { error = EIO; goto errout; } #ifdef LUFS /* * Free up the allocated space (dummy inode needed for free()) */ ip = qfs_alloc_inode(qfsvfsp, QFSROOTINO); #else /* * QFS doesn't need an inode to free blocks. */ #endif /* LUFS */ ebp = (void *)bp->b_un.b_addr; for (i = 0, ep = &ebp->extents[0]; i < ebp->nextents; ++i, ++ep) { fno = logbtofrag(fs, ep->pbno); nfno = dbtofsb(fs, ep->nbno); for (j = 0; j < nfno; j += FS_FRAG(fs), fno += FS_FRAG(fs)) { #ifdef LUFS free(ip, fno, FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, fno), ep->ord); #endif /* LUFS */ } } #ifdef LUFS free(ip, logbtofrag(fs, logbno), FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, logbno), logord); #endif /* LUFS */ brelse(bp); bp = NULL; /* * Push the metadata dirtied during the allocations */ UL_SBOWNER_SET(qfsvfsp, curthread); #ifdef LUFS sbupdate(qfsvfsp->vfs_vfs); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); #endif /* LUFS */ UL_SBOWNER_SET(qfsvfsp, -1); bflush(qfsvfsp->mi.m_fs[logord].dev); error = bfinval(qfsvfsp->mi.m_fs[logord].dev, 0); if (error) { goto errout; } /* * Free the dummy inode */ #ifdef LUFS qfs_free_inode(ip); #else /* QFS uses a reserved inode */ VN_RELE(SAM_ITOV(ip)); #endif /* LUFS */ return (0); errout: /* * Free up all resources */ if (bp) { brelse(bp); } if (ip) { #ifdef LUFS qfs_free_inode(ip); #else /* QFS uses a reserved inode */ VN_RELE(SAM_ITOV(ip)); #endif /* LUFS */ } return (error); }