123396Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423396Smckusick * 537736Smckusick * Redistribution and use in source and binary forms are permitted 637736Smckusick * provided that the above copyright notice and this paragraph are 737736Smckusick * duplicated in all such forms and that any documentation, 837736Smckusick * advertising materials, and other materials related to such 937736Smckusick * distribution and use acknowledge that the software was developed 1037736Smckusick * by the University of California, Berkeley. The name of the 1137736Smckusick * University may not be used to endorse or promote products derived 1237736Smckusick * from this software without specific prior written permission. 1337736Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437736Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537736Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637736Smckusick * 17*38776Smckusick * @(#)lfs_balloc.c 7.5 (Berkeley) 08/26/89 1823396Smckusick */ 197443Sroot 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "user.h" 2317099Sbloom #include "buf.h" 2417099Sbloom #include "proc.h" 2537736Smckusick #include "file.h" 2637736Smckusick #include "vnode.h" 2737736Smckusick #include "../ufs/inode.h" 2837736Smckusick #include "../ufs/fs.h" 297443Sroot 307443Sroot /* 317443Sroot * Bmap defines the structure of file system storage 327443Sroot * by returning the physical block number on a device given the 337443Sroot * inode and the logical block number in a file. 347443Sroot * When convenient, it also leaves the physical 357443Sroot * block number of the next block of the file in rablock 367443Sroot * for use in read-ahead. 377443Sroot */ 3837736Smckusick bmap(ip, bn, bnp, rablockp, rasizep) 397443Sroot register struct inode *ip; 4037736Smckusick register daddr_t bn; 4137736Smckusick daddr_t *bnp; 4237736Smckusick daddr_t *rablockp; 4337736Smckusick int *rasizep; 447443Sroot { 4537736Smckusick register struct fs *fs; 4637736Smckusick register daddr_t nb; 4737736Smckusick struct buf *bp; 4837736Smckusick daddr_t *bap; 4937736Smckusick int i, j, sh; 5037736Smckusick int error; 5137736Smckusick 5237736Smckusick if (bn < 0) 5337736Smckusick return (EFBIG); 5437736Smckusick fs = ip->i_fs; 5537736Smckusick 5637736Smckusick /* 5737736Smckusick * The first NDADDR blocks are direct blocks 5837736Smckusick */ 5937736Smckusick if (bn < NDADDR) { 6037736Smckusick nb = ip->i_db[bn]; 6137736Smckusick if (nb == 0) { 6237736Smckusick *bnp = (daddr_t)-1; 6337736Smckusick return (0); 6437736Smckusick } 6537736Smckusick if (rablockp && rasizep) { 6637736Smckusick if (bn < NDADDR - 1) { 6737736Smckusick *rablockp = fsbtodb(fs, ip->i_db[bn + 1]); 6837736Smckusick *rasizep = blksize(fs, ip, bn + 1); 6937736Smckusick } else { 7037736Smckusick *rablockp = 0; 7137736Smckusick *rasizep = 0; 7237736Smckusick } 7337736Smckusick } 7437736Smckusick *bnp = fsbtodb(fs, nb); 7537736Smckusick return (0); 7637736Smckusick } 7737736Smckusick 7837736Smckusick /* 7937736Smckusick * Determine how many levels of indirection. 8037736Smckusick */ 8137736Smckusick sh = 1; 8237736Smckusick bn -= NDADDR; 8337736Smckusick for (j = NIADDR; j > 0; j--) { 8437736Smckusick sh *= NINDIR(fs); 8537736Smckusick if (bn < sh) 8637736Smckusick break; 8737736Smckusick bn -= sh; 8837736Smckusick } 8937736Smckusick if (j == 0) 9037736Smckusick return (EFBIG); 9137736Smckusick 9237736Smckusick /* 9337736Smckusick * fetch the first indirect block 9437736Smckusick */ 9537736Smckusick nb = ip->i_ib[NIADDR - j]; 9637736Smckusick if (nb == 0) { 9737736Smckusick *bnp = (daddr_t)-1; 9837736Smckusick return (0); 9937736Smckusick } 10037736Smckusick 10137736Smckusick /* 10237736Smckusick * fetch through the indirect blocks 10337736Smckusick */ 10437736Smckusick for (; j <= NIADDR; j++) { 10537736Smckusick if (error = bread(ip->i_devvp, fsbtodb(fs, nb), 106*38776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 10737736Smckusick brelse(bp); 10837736Smckusick return (error); 10937736Smckusick } 11037736Smckusick bap = bp->b_un.b_daddr; 11137736Smckusick sh /= NINDIR(fs); 11237736Smckusick i = (bn / sh) % NINDIR(fs); 11337736Smckusick nb = bap[i]; 11437736Smckusick if (nb == 0) { 11537736Smckusick *bnp = (daddr_t)-1; 11637736Smckusick brelse(bp); 11737736Smckusick return (0); 11837736Smckusick } 11938448Smckusick if (j < NIADDR) 12038448Smckusick brelse(bp); 12137736Smckusick } 12237736Smckusick 12337736Smckusick /* 12437736Smckusick * calculate read-ahead. 12537736Smckusick */ 12637736Smckusick if (rablockp && rasizep) { 12737736Smckusick if (i < NINDIR(fs) - 1) { 12837736Smckusick *rablockp = fsbtodb(fs, bap[i + 1]); 12937736Smckusick *rasizep = fs->fs_bsize; 13037736Smckusick } else { 13137736Smckusick *rablockp = 0; 13237736Smckusick *rasizep = 0; 13337736Smckusick } 13437736Smckusick } 13537736Smckusick *bnp = fsbtodb(fs, nb); 13637736Smckusick brelse(bp); 13737736Smckusick return (0); 13837736Smckusick } 13937736Smckusick 14037736Smckusick /* 14137736Smckusick * Balloc defines the structure of file system storage 14237736Smckusick * by returning the physical block number on a device given the 14337736Smckusick * inode and the logical block number in a file. 14437736Smckusick * When unallocated entries are found, new physical blocks 14537736Smckusick * are allocated. 14637736Smckusick */ 14737736Smckusick balloc(ip, bn, size, bnp, flags) 14837736Smckusick register struct inode *ip; 14937736Smckusick register daddr_t bn; 15037736Smckusick int size; 15137736Smckusick daddr_t *bnp; 15237736Smckusick int flags; 15337736Smckusick { 15437736Smckusick register struct fs *fs; 15537736Smckusick register daddr_t nb; 1567443Sroot struct buf *bp, *nbp; 15737736Smckusick int osize, nsize, i, j, sh, error; 15837736Smckusick daddr_t lbn, *bap, pref, blkpref(); 1597443Sroot 16037736Smckusick if (bn < 0) 16137736Smckusick return (EFBIG); 1627443Sroot fs = ip->i_fs; 1637443Sroot 1647443Sroot /* 1657443Sroot * If the next write will extend the file into a new block, 1667443Sroot * and the file is currently composed of a fragment 1677443Sroot * this fragment has to be extended to be a full block. 1687443Sroot */ 1697443Sroot nb = lblkno(fs, ip->i_size); 17037736Smckusick if (nb < NDADDR && nb < bn) { 1717443Sroot osize = blksize(fs, ip, nb); 1727443Sroot if (osize < fs->fs_bsize && osize > 0) { 17337736Smckusick error = realloccg(ip, ip->i_db[nb], 1749165Ssam blkpref(ip, nb, (int)nb, &ip->i_db[0]), 17537736Smckusick osize, (int)fs->fs_bsize, &bp); 17637736Smckusick if (error) { 17737736Smckusick *bnp = (daddr_t)-1; 17837736Smckusick return (error); 17937736Smckusick } 1807443Sroot ip->i_size = (nb + 1) * fs->fs_bsize; 1817443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 1827443Sroot ip->i_flag |= IUPD|ICHG; 1837443Sroot bdwrite(bp); 1847443Sroot } 1857443Sroot } 1867443Sroot /* 1877443Sroot * The first NDADDR blocks are direct blocks 1887443Sroot */ 1897443Sroot if (bn < NDADDR) { 1908258Smckusick nb = ip->i_db[bn]; 1918258Smckusick if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 1927443Sroot if (nb != 0) { 1937443Sroot /* consider need to reallocate a frag */ 1947443Sroot osize = fragroundup(fs, blkoff(fs, ip->i_size)); 1957443Sroot nsize = fragroundup(fs, size); 1967443Sroot if (nsize <= osize) 1977443Sroot goto gotit; 19837736Smckusick error = realloccg(ip, nb, 1999165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 20037736Smckusick osize, nsize, &bp); 2017443Sroot } else { 2028258Smckusick if (ip->i_size < (bn + 1) * fs->fs_bsize) 2037443Sroot nsize = fragroundup(fs, size); 2047443Sroot else 2057443Sroot nsize = fs->fs_bsize; 20637736Smckusick error = alloc(ip, 2079165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 20837736Smckusick nsize, &bp, flags); 2097443Sroot } 21037736Smckusick if (error) { 21137736Smckusick *bnp = (daddr_t)-1; 21237736Smckusick return (error); 21337736Smckusick } 2147443Sroot nb = dbtofsb(fs, bp->b_blkno); 21537736Smckusick if ((ip->i_mode & IFMT) == IFDIR) 2167443Sroot /* 2177443Sroot * Write directory blocks synchronously 2187443Sroot * so they never appear with garbage in 2197443Sroot * them on the disk. 22037736Smckusick * 22137736Smckusick * NB: Should free space and return error 22237736Smckusick * if bwrite returns an error. 2237443Sroot */ 22437736Smckusick error = bwrite(bp); 2257443Sroot else 2267443Sroot bdwrite(bp); 2278258Smckusick ip->i_db[bn] = nb; 2287443Sroot ip->i_flag |= IUPD|ICHG; 2297443Sroot } 2307443Sroot gotit: 23137736Smckusick *bnp = fsbtodb(fs, nb); 23237736Smckusick return (0); 2337443Sroot } 2347443Sroot 2357443Sroot /* 2367443Sroot * Determine how many levels of indirection. 2377443Sroot */ 2388258Smckusick pref = 0; 2397443Sroot sh = 1; 2408258Smckusick lbn = bn; 2417443Sroot bn -= NDADDR; 24237736Smckusick for (j = NIADDR; j > 0; j--) { 2437443Sroot sh *= NINDIR(fs); 2447443Sroot if (bn < sh) 2457443Sroot break; 2467443Sroot bn -= sh; 2477443Sroot } 24837736Smckusick if (j == 0) 24937736Smckusick return (EFBIG); 2507443Sroot 2517443Sroot /* 2527443Sroot * fetch the first indirect block 2537443Sroot */ 2547443Sroot nb = ip->i_ib[NIADDR - j]; 2557443Sroot if (nb == 0) { 2569165Ssam pref = blkpref(ip, lbn, 0, (daddr_t *)0); 25737736Smckusick error = alloc(ip, pref, (int)fs->fs_bsize, &bp, B_CLRBUF); 25837736Smckusick if (error) { 25937736Smckusick *bnp = (daddr_t)-1; 26037736Smckusick return (error); 26137736Smckusick } 2627443Sroot nb = dbtofsb(fs, bp->b_blkno); 2637443Sroot /* 2647443Sroot * Write synchronously so that indirect blocks 2657443Sroot * never point at garbage. 26637736Smckusick * 26737736Smckusick * NB: Should free space and return error 26837736Smckusick * if bwrite returns an error. 2697443Sroot */ 27037736Smckusick error = bwrite(bp); 2717443Sroot ip->i_ib[NIADDR - j] = nb; 2727443Sroot ip->i_flag |= IUPD|ICHG; 2737443Sroot } 2747443Sroot 2757443Sroot /* 2767443Sroot * fetch through the indirect blocks 2777443Sroot */ 2787443Sroot for (; j <= NIADDR; j++) { 27937736Smckusick if (error = bread(ip->i_devvp, fsbtodb(fs, nb), 280*38776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 2817443Sroot brelse(bp); 28237736Smckusick return (error); 2837443Sroot } 2847443Sroot bap = bp->b_un.b_daddr; 2857443Sroot sh /= NINDIR(fs); 2867443Sroot i = (bn / sh) % NINDIR(fs); 2877443Sroot nb = bap[i]; 2887443Sroot if (nb == 0) { 2898258Smckusick if (pref == 0) 2908258Smckusick if (j < NIADDR) 2919165Ssam pref = blkpref(ip, lbn, 0, 2929165Ssam (daddr_t *)0); 2938258Smckusick else 2948258Smckusick pref = blkpref(ip, lbn, i, &bap[0]); 29537736Smckusick error = alloc(ip, pref, (int)fs->fs_bsize, &nbp, 29637736Smckusick (j < NIADDR) ? B_CLRBUF : flags); 29737736Smckusick if (error) { 2987443Sroot brelse(bp); 29937736Smckusick *bnp = (daddr_t)-1; 30037736Smckusick return (error); 3017443Sroot } 3027443Sroot nb = dbtofsb(fs, nbp->b_blkno); 30337736Smckusick if (j < NIADDR || (ip->i_mode & IFMT) == IFDIR) 3047443Sroot /* 3057443Sroot * Write synchronously so indirect blocks 3067443Sroot * never point at garbage and blocks 3077443Sroot * in directories never contain garbage. 30837736Smckusick * 30937736Smckusick * NB: Should free space and return error 31037736Smckusick * if bwrite returns an error. 3117443Sroot */ 31237736Smckusick error = bwrite(nbp); 3137443Sroot else 3147443Sroot bdwrite(nbp); 3157443Sroot bap[i] = nb; 3167443Sroot bdwrite(bp); 3177443Sroot } else 3187443Sroot brelse(bp); 3197443Sroot } 3207443Sroot 32137736Smckusick *bnp = fsbtodb(fs, nb); 32237736Smckusick return (0); 3237443Sroot } 324