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