Check for out of space condition before extending ifile.
[unix-history] / usr / src / sys / ufs / lfs / lfs_alloc.c
CommitLineData
da7c5cc6 1/*
4bed3ffc 2 * Copyright (c) 1991 Regents of the University of California.
202a4bd9 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
202a4bd9 6 *
a18538c9 7 * @(#)lfs_alloc.c 7.54 (Berkeley) %G%
da7c5cc6 8 */
e3fe2d69 9
ddd9f644
KB
10#include <sys/param.h>
11#include <sys/kernel.h>
12#include <sys/buf.h>
13#include <sys/vnode.h>
14#include <sys/syslog.h>
15#include <sys/mount.h>
4c5ed28a 16#include <sys/malloc.h>
c6f5111d 17
80e9de4e
KM
18#include <vm/vm.h>
19
4bed3ffc
KB
20#include <ufs/ufs/quota.h>
21#include <ufs/ufs/inode.h>
22#include <ufs/ufs/ufsmount.h>
ddd9f644 23
4bed3ffc
KB
24#include <ufs/lfs/lfs.h>
25#include <ufs/lfs/lfs_extern.h>
26
27extern u_long nextgennumber;
ddd9f644
KB
28
29/* Allocate a new inode. */
30/* ARGSUSED */
31int
fc250aa9
MS
32lfs_valloc(ap)
33 struct vop_valloc_args /* {
34 struct vnode *a_pvp;
35 int a_mode;
36 struct ucred *a_cred;
37 struct vnode **a_vpp;
38 } */ *ap;
e3fe2d69 39{
4bed3ffc 40 struct lfs *fs;
889a3fb1
KB
41 struct buf *bp;
42 struct ifile *ifp;
43 struct inode *ip;
44 struct vnode *vp;
45 daddr_t blkno;
0b4d6502 46 ino_t new_ino;
889a3fb1 47 u_long i, max;
a18538c9 48 int bb, error;
e3fe2d69 49
275ca4f0 50 /* Get the head of the freelist. */
e1b76915 51 fs = VTOI(ap->a_pvp)->i_lfs;
0b4d6502 52 new_ino = fs->lfs_free;
ddd9f644
KB
53#ifdef ALLOCPRINT
54 printf("lfs_ialloc: allocate inode %d\n", new_ino);
55#endif
0b4d6502 56
1344ae31 57 /*
889a3fb1
KB
58 * Remove the inode from the free list and write the new start
59 * of the free list into the superblock.
1344ae31 60 */
0b4d6502 61 LFS_IENTRY(ifp, fs, new_ino, bp);
0b4d6502 62 if (ifp->if_daddr != LFS_UNUSED_DADDR)
275ca4f0 63 panic("lfs_ialloc: inuse inode on the free list");
0b4d6502 64 fs->lfs_free = ifp->if_nextfree;
889a3fb1
KB
65 brelse(bp);
66
67 /* Extend IFILE so that the next lfs_valloc will succeed. */
68 if (fs->lfs_free == LFS_UNUSED_INUM) {
a18538c9
MS
69 bb = fsbtodb(fs, 1);
70 if (!ISSPACE(fs, bb, ap->a_cred))
71 return(ENOSPC);
889a3fb1
KB
72 vp = fs->lfs_ivnode;
73 ip = VTOI(vp);
74 blkno = lblkno(fs, ip->i_size);
889a3fb1 75 bp = getblk(vp, blkno, fs->lfs_bsize);
889a3fb1
KB
76 i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) *
77 fs->lfs_ifpb;
889a3fb1
KB
78 fs->lfs_free = i;
79 max = i + fs->lfs_ifpb;
889a3fb1
KB
80 for (ifp = (struct ifile *)bp->b_un.b_words; i < max; ++ifp) {
81 ifp->if_version = 1;
82 ifp->if_daddr = LFS_UNUSED_DADDR;
83 ifp->if_nextfree = ++i;
84 }
85 ifp--;
86 ifp->if_nextfree = LFS_UNUSED_INUM;
87
27273279 88 ip->i_blocks += btodb(fs->lfs_bsize);
a5d64982 89 fs->lfs_bfree -= btodb(fs->lfs_bsize);
889a3fb1 90 ip->i_size += fs->lfs_bsize;
80e9de4e 91 vnode_pager_setsize(vp, (u_long)ip->i_size);
889a3fb1 92 vnode_pager_uncache(vp);
03dc7bb7
KB
93 if (error = VOP_BWRITE(bp))
94 return (error);
889a3fb1 95 }
07670f7d 96
275ca4f0 97 /* Create a vnode to associate with the inode. */
e1b76915 98 if (error = lfs_vcreate(ap->a_pvp->v_mount, new_ino, &vp))
7188ac27 99 return (error);
e1b76915 100 *ap->a_vpp = vp;
fc250aa9 101 vp->v_flag |= VDIROP;
a58cc97d
KM
102 ip = VTOI(vp);
103 VREF(ip->i_devvp);
0b4d6502 104
889a3fb1
KB
105 /* Zero out the direct and indirect block addresses. */
106 bzero(ip->i_db, (NDADDR + NIADDR) * sizeof(daddr_t));
107
275ca4f0 108 /* Set a new generation number for this inode. */
fb92d0ab
KM
109 if (++nextgennumber < (u_long)time.tv_sec)
110 nextgennumber = time.tv_sec;
111 ip->i_gen = nextgennumber;
e3fe2d69 112
275ca4f0 113 /* Insert into the inode hash table. */
ddd9f644 114 ufs_ihashins(ip);
743f1ef7 115
275ca4f0
KB
116 /* Set superblock modified bit and increment file count. */
117 fs->lfs_fmod = 1;
118 ++fs->lfs_nfiles;
0b4d6502 119 return (0);
e3fe2d69
KM
120}
121
275ca4f0 122/* Create a new vnode/inode pair and initialize what fields we can. */
0a0d4fba 123int
0b4d6502 124lfs_vcreate(mp, ino, vpp)
889a3fb1 125 struct mount *mp;
0b4d6502 126 ino_t ino;
889a3fb1 127 struct vnode **vpp;
e3fe2d69 128{
9342689a 129 extern int (**lfs_vnodeop_p)();
889a3fb1
KB
130 struct inode *ip;
131 struct ufsmount *ump;
0b4d6502
KB
132 int error, i;
133
275ca4f0 134 /* Create the vnode. */
9342689a 135 if (error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, vpp)) {
4c5ed28a 136 *vpp = NULL;
5e1f6927 137 return (error);
4c5ed28a 138 }
0b4d6502 139
275ca4f0 140 /* Get a pointer to the private mount structure. */
0b4d6502
KB
141 ump = VFSTOUFS(mp);
142
143 /* Initialize the inode. */
4c5ed28a
KM
144 MALLOC(ip, struct inode *, sizeof(struct inode), M_LFSNODE, M_WAITOK);
145 (*vpp)->v_data = ip;
a58cc97d 146 ip->i_vnode = *vpp;
1ef966ee 147 ip->i_devvp = ump->um_devvp;
03dc7bb7 148 ip->i_flag = IMOD;
a58cc97d 149 ip->i_dev = ump->um_dev;
d5075120 150 ip->i_number = ip->i_din.di_inum = ino;
a58cc97d 151 ip->i_lfs = ump->um_lfs;
0b4d6502
KB
152#ifdef QUOTA
153 for (i = 0; i < MAXQUOTAS; i++)
154 ip->i_dquot[i] = NODQUOT;
155#endif
1ef966ee
KB
156 ip->i_lockf = 0;
157 ip->i_diroff = 0;
158 ip->i_mode = 0;
159 ip->i_size = 0;
a5d64982 160 ip->i_blocks = 0;
03dc7bb7 161 ++ump->um_lfs->lfs_uinodes;
0b4d6502 162 return (0);
e3fe2d69 163}
d5075120 164
ddd9f644
KB
165/* Free an inode. */
166/* ARGUSED */
988dbbfa 167int
fc250aa9
MS
168lfs_vfree(ap)
169 struct vop_vfree_args /* {
170 struct vnode *a_pvp;
171 ino_t a_ino;
172 int a_mode;
173 } */ *ap;
275ca4f0 174{
01932c99 175 SEGUSE *sup;
889a3fb1
KB
176 struct buf *bp;
177 struct ifile *ifp;
178 struct inode *ip;
4bed3ffc 179 struct lfs *fs;
01932c99 180 daddr_t old_iaddr;
275ca4f0 181 ino_t ino;
03dc7bb7 182 int error;
275ca4f0 183
ddd9f644 184 /* Get the inode number and file system. */
fa870596 185 ip = VTOI(ap->a_pvp);
275ca4f0
KB
186 fs = ip->i_lfs;
187 ino = ip->i_number;
03dc7bb7
KB
188 if (ip->i_flag & IMOD) {
189 --fs->lfs_uinodes;
190 ip->i_flag &= ~(IMOD | IACC | IUPD | ICHG);
191 }
ddd9f644 192 /*
1344ae31
KB
193 * Set the ifile's inode entry to unused, increment its version number
194 * and link it into the free chain.
ddd9f644 195 */
275ca4f0 196 LFS_IENTRY(ifp, fs, ino, bp);
01932c99 197 old_iaddr = ifp->if_daddr;
ddd9f644
KB
198 ifp->if_daddr = LFS_UNUSED_DADDR;
199 ++ifp->if_version;
200 ifp->if_nextfree = fs->lfs_free;
201 fs->lfs_free = ino;
03dc7bb7 202 (void) VOP_BWRITE(bp);
ddd9f644 203
01932c99
CS
204 if (old_iaddr != LFS_UNUSED_DADDR) {
205 LFS_SEGENTRY(sup, fs, datosn(fs, old_iaddr), bp);
206#ifdef DIAGNOSTIC
207 if (sup->su_nbytes < sizeof(struct dinode))
208 panic("lfs_vfree: negative byte count (segment %d)\n",
209 datosn(fs, old_iaddr));
210#endif
211 sup->su_nbytes -= sizeof(struct dinode);
03dc7bb7 212 (void) VOP_BWRITE(bp);
01932c99
CS
213 }
214
ddd9f644
KB
215 /* Set superblock modified bit and decrement file count. */
216 fs->lfs_fmod = 1;
217 --fs->lfs_nfiles;
988dbbfa 218 return (0);
275ca4f0 219}