1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_syscalls.c 7.18 (Berkeley) 08/01/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/proc.h> 12 #include <sys/buf.h> 13 #include <sys/mount.h> 14 #include <sys/vnode.h> 15 #include <sys/malloc.h> 16 #include <sys/kernel.h> 17 18 #include <ufs/ufs/quota.h> 19 #include <ufs/ufs/inode.h> 20 #include <ufs/ufs/ufsmount.h> 21 22 #include <ufs/lfs/lfs.h> 23 #include <ufs/lfs/lfs_extern.h> 24 25 /* 26 * lfs_markv: 27 * 28 * This will mark inodes and blocks dirty, so they are written into the log. 29 * It will block until all the blocks have been written. The segment create 30 * time passed in the block_info and inode_info structures is used to decide 31 * if the data is valid for each block (in case some process dirtied a block 32 * or inode that is being cleaned between the determination that a block is 33 * live and the lfs_markv call). 34 * 35 * 0 on success 36 * -1/errno is return on error. 37 */ 38 int 39 lfs_markv(p, uap, retval) 40 struct proc *p; 41 struct args { 42 fsid_t fsid; /* file system */ 43 BLOCK_INFO *blkiov; /* block array */ 44 int blkcnt; /* count of block array entries */ 45 INODE_INFO *inoiov; /* inode array */ 46 int inocnt; /* count of inode array entries */ 47 } *uap; 48 int *retval; 49 { 50 BLOCK_INFO *blkp; 51 IFILE *ifp; 52 INODE_INFO *inop; 53 struct buf *bp; 54 struct inode *ip; 55 struct lfs *fs; 56 struct mount *mntp; 57 struct vnode *vp; 58 void *start; 59 ino_t lastino; 60 daddr_t daddr; 61 u_long bsize; 62 int cnt, error; 63 64 if (error = suser(p->p_ucred, &p->p_acflag)) 65 return (error); 66 67 if ((mntp = getvfs(&uap->fsid)) == NULL) 68 return (EINVAL); 69 70 cnt = uap->blkcnt; 71 start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 72 if (error = copyin(uap->blkiov, start, cnt * sizeof(BLOCK_INFO))) { 73 free(start, M_SEGMENT); 74 return (error); 75 } 76 77 /* 78 * Mark blocks/inodes dirty. Note that errors are mostly ignored. If 79 * we can't get the info, the block is probably not all that useful, 80 * and hopefully subsequent calls from the cleaner will fix everything. 81 */ 82 fs = VFSTOUFS(mntp)->um_lfs; 83 bsize = fs->lfs_bsize; 84 for (lastino = LFS_UNUSED_INUM, blkp = start; cnt--; ++blkp) { 85 /* 86 * Get the IFILE entry (only once) and see if the file still 87 * exists. 88 */ 89 if (lastino != blkp->bi_inode) { 90 lastino = blkp->bi_inode; 91 LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 92 daddr = ifp->if_daddr; 93 brelse(bp); 94 if (daddr == LFS_UNUSED_DADDR) 95 continue; 96 } 97 98 /* 99 * Get the vnode/inode. If the inode modification time is 100 * earlier than the segment in which the block was found then 101 * they have to be valid, skip other checks. 102 */ 103 if (VFS_VGET(mntp, blkp->bi_inode, &vp)) 104 continue; 105 ip = VTOI(vp); 106 107 /* 108 * If modify time later than segment create time, see if the 109 * block has been replaced. 110 */ 111 if (ip->i_mtime.ts_sec > blkp->bi_segcreate && 112 (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr) || 113 daddr != blkp->bi_daddr)) { 114 vput(vp); 115 continue; 116 } 117 118 /* Get the block (from core or the cleaner) and write it. */ 119 bp = getblk(vp, blkp->bi_lbn, bsize); 120 vput(vp); 121 if (!(bp->b_flags & B_CACHE) && 122 (error = copyin(blkp->bi_bp, bp->b_un.b_addr, bsize))) { 123 brelse(bp); 124 free(start, M_SEGMENT); 125 return (error); 126 } 127 VOP_BWRITE(bp); 128 } 129 free(start, M_SEGMENT); 130 131 cnt = uap->inocnt; 132 start = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK); 133 if (error = copyin(uap->inoiov, start, cnt * sizeof(INODE_INFO))) { 134 free(start, M_SEGMENT); 135 return (error); 136 } 137 138 for (inop = start; cnt--; ++inop) { 139 if (inop->ii_inode == LFS_IFILE_INUM) 140 daddr = fs->lfs_idaddr; 141 else { 142 LFS_IENTRY(ifp, fs, inop->ii_inode, bp); 143 daddr = ifp->if_daddr; 144 brelse(bp); 145 } 146 147 if (daddr != inop->ii_daddr) 148 continue; 149 /* 150 * XXX 151 * This is grossly inefficient since the cleaner just handed 152 * us a copy of the inode and we're going to have to seek 153 * to get our own. The fix requires creating a version of 154 * lfs_vget that takes the copy and uses it instead of reading 155 * from disk, if it's not already in the cache. 156 */ 157 if (!VFS_VGET(mntp, inop->ii_inode, &vp)) { 158 VTOI(vp)->i_flag |= IMOD; 159 vput(vp); 160 } 161 } 162 free(start, M_SEGMENT); 163 return (lfs_segwrite(mntp, 1)); 164 } 165 166 /* 167 * lfs_bmapv: 168 * 169 * This will fill in the current disk address for arrays of blocks. 170 * 171 * 0 on success 172 * -1/errno is return on error. 173 */ 174 int 175 lfs_bmapv(p, uap, retval) 176 struct proc *p; 177 struct args { 178 fsid_t fsid; /* file system */ 179 BLOCK_INFO *blkiov; /* block array */ 180 int blkcnt; /* count of block array entries */ 181 } *uap; 182 int *retval; 183 { 184 BLOCK_INFO *blkp; 185 struct mount *mntp; 186 struct vnode *vp; 187 void *start; 188 daddr_t daddr; 189 int cnt, error, step; 190 191 if (error = suser(p->p_ucred, &p->p_acflag)) 192 return (error); 193 194 if ((mntp = getvfs(&uap->fsid)) == NULL) 195 return (EINVAL); 196 197 cnt = uap->blkcnt; 198 start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 199 if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 200 free(blkp, M_SEGMENT); 201 return (error); 202 } 203 204 for (step = cnt; step--; ++blkp) { 205 if (VFS_VGET(mntp, blkp->bi_inode, &vp)) 206 daddr = LFS_UNUSED_DADDR; 207 else { 208 if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr)) 209 daddr = LFS_UNUSED_DADDR; 210 vput(vp); 211 } 212 blkp->bi_daddr = daddr; 213 } 214 copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO)); 215 free(start, M_SEGMENT); 216 return (0); 217 } 218 219 /* 220 * lfs_segclean: 221 * 222 * Mark the segment clean. 223 * 224 * 0 on success 225 * -1/errno is return on error. 226 */ 227 int 228 lfs_segclean(p, uap, retval) 229 struct proc *p; 230 struct args { 231 fsid_t fsid; /* file system */ 232 u_long segment; /* segment number */ 233 } *uap; 234 int *retval; 235 { 236 CLEANERINFO *cip; 237 SEGUSE *sup; 238 struct buf *bp; 239 struct mount *mntp; 240 struct lfs *fs; 241 int error; 242 243 if (error = suser(p->p_ucred, &p->p_acflag)) 244 return (error); 245 246 if ((mntp = getvfs(&uap->fsid)) == NULL) 247 return (EINVAL); 248 249 fs = VFSTOUFS(mntp)->um_lfs; 250 251 LFS_SEGENTRY(sup, fs, uap->segment, bp); 252 fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) + 253 sup->su_ninos * btodb(fs->lfs_bsize); 254 sup->su_flags &= ~SEGUSE_DIRTY; 255 sup->su_nbytes -= sup->su_nsums * LFS_SUMMARY_SIZE; 256 sup->su_ninos = 0; 257 sup->su_nsums = 0; 258 LFS_UBWRITE(bp); 259 260 LFS_CLEANERINFO(cip, fs, bp); 261 ++cip->clean; 262 --cip->dirty; 263 LFS_UBWRITE(bp); 264 return (0); 265 } 266 267 /* 268 * lfs_segwait: 269 * 270 * This will block until a segment in file system fsid is written. A timeout 271 * in milliseconds may be specified which will awake the cleaner automatically. 272 * An fsid of -1 means any file system, and a timeout of 0 means forever. 273 * 274 * 0 on success 275 * 1 on timeout 276 * -1/errno is return on error. 277 */ 278 int 279 lfs_segwait(p, uap, retval) 280 struct proc *p; 281 struct args { 282 fsid_t fsid; /* file system */ 283 struct timeval *tv; /* timeout */ 284 } *uap; 285 int *retval; 286 { 287 extern int lfs_allclean_wakeup; 288 struct mount *mntp; 289 struct timeval atv; 290 void *addr; 291 u_long timeout; 292 int error, s; 293 294 if (error = suser(p->p_ucred, &p->p_acflag)) 295 return (error); 296 297 #ifdef WHEN_QUADS_WORK 298 if (uap->fsid == (fsid_t)-1) 299 addr = &lfs_allclean_wakeup; 300 else { 301 if ((mntp = getvfs(&uap->fsid)) == NULL) 302 return (EINVAL); 303 addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 304 } 305 #else 306 if ((mntp = getvfs(&uap->fsid)) == NULL) 307 addr = &lfs_allclean_wakeup; 308 else 309 addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 310 #endif 311 312 if (uap->tv) { 313 if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 314 return (error); 315 if (itimerfix(&atv)) 316 return (EINVAL); 317 s = splclock(); 318 timevaladd(&atv, (struct timeval *)&time); 319 timeout = hzto(&atv); 320 splx(s); 321 } else 322 timeout = 0; 323 324 error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 325 return (error == ERESTART ? EINTR : 0); 326 } 327