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