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