Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/fs/msdosfs/msdosfs_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/fs/msdosfs/msdosfs_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.19 retrieving revision 1.61.4.6 diff -u -p -r1.19 -r1.61.4.6 --- src/sys/fs/msdosfs/msdosfs_vnops.c 2005/09/10 18:35:56 1.19 +++ src/sys/fs/msdosfs/msdosfs_vnops.c 2011/05/31 03:04:59 1.61.4.6 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_vnops.c,v 1.19 2005/09/10 18:35:56 christos Exp $ */ +/* $NetBSD: msdosfs_vnops.c,v 1.61.4.6 2011/05/31 03:04:59 rmind Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. @@ -48,7 +48,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.19 2005/09/10 18:35:56 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.61.4.6 2011/05/31 03:04:59 rmind Exp $"); #include #include @@ -60,11 +60,13 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnop #include #include #include +#include #include #include #include #include #include +#include #include #include /* XXX */ /* defines v_rdev */ @@ -97,13 +99,10 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnop /* * Create a regular file. On entry the directory to contain the file being - * created is locked. We must release before we return. We must also free - * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or - * only if the SAVESTART bit in cn_flags is clear on success. + * created is locked. We must release before we return. */ int -msdosfs_create(v) - void *v; +msdosfs_create(void *v) { struct vop_create_args /* { struct vnode *a_dvp; @@ -116,12 +115,12 @@ msdosfs_create(v) struct denode *dep; struct denode *pdep = VTODE(ap->a_dvp); int error; - struct timespec ts; #ifdef MSDOSFS_DEBUG printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap); #endif + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not @@ -139,10 +138,6 @@ msdosfs_create(v) * use the absence of the owner write bit to make the file * readonly. */ -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & HASBUF) == 0) - panic("msdosfs_create: no name"); -#endif memset(&ndirent, 0, sizeof(ndirent)); if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0) goto bad; @@ -155,92 +150,44 @@ msdosfs_create(v) ndirent.de_devvp = pdep->de_devvp; ndirent.de_pmp = pdep->de_pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; - TIMEVAL_TO_TIMESPEC(&time, &ts); - DETIMES(&ndirent, &ts, &ts, &ts, pdep->de_pmp->pm_gmtoff); + DETIMES(&ndirent, NULL, NULL, NULL, pdep->de_pmp->pm_gmtoff); if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) goto bad; - if ((cnp->cn_flags & SAVESTART) == 0) - PNBUF_PUT(cnp->cn_pnbuf); + fstrans_done(ap->a_dvp->v_mount); VN_KNOTE(ap->a_dvp, NOTE_WRITE); vput(ap->a_dvp); *ap->a_vpp = DETOV(dep); return (0); bad: - PNBUF_PUT(cnp->cn_pnbuf); + fstrans_done(ap->a_dvp->v_mount); vput(ap->a_dvp); return (error); } int -msdosfs_mknod(v) - void *v; -{ - struct vop_mknod_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - } */ *ap = v; - - PNBUF_PUT(ap->a_cnp->cn_pnbuf); - vput(ap->a_dvp); - return (EINVAL); -} - -int -msdosfs_open(v) - void *v; -{ -#if 0 - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -#endif - - return (0); -} - -int -msdosfs_close(v) - void *v; +msdosfs_close(void *v) { struct vop_close_args /* { struct vnode *a_vp; int a_fflag; - struct ucred *a_cred; - struct proc *a_p; + kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct denode *dep = VTODE(vp); - struct timespec ts; - simple_lock(&vp->v_interlock); - if (vp->v_usecount > 1) { - TIMEVAL_TO_TIMESPEC(&time, &ts); - DETIMES(dep, &ts, &ts, &ts, dep->de_pmp->pm_gmtoff); - } - simple_unlock(&vp->v_interlock); + fstrans_start(vp->v_mount, FSTRANS_SHARED); + mutex_enter(vp->v_interlock); + if (vp->v_usecount > 1) + DETIMES(dep, NULL, NULL, NULL, dep->de_pmp->pm_gmtoff); + mutex_exit(vp->v_interlock); + fstrans_done(vp->v_mount); return (0); } -int -msdosfs_access(v) - void *v; +static int +msdosfs_check_possible(struct vnode *vp, struct denode *dep, mode_t mode) { - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap = v; - struct vnode *vp = ap->a_vp; - struct denode *dep = VTODE(vp); - struct msdosfsmount *pmp = dep->de_pmp; - mode_t mode = ap->a_mode; /* * Disallow write attempts on read-only file systems; @@ -259,35 +206,64 @@ msdosfs_access(v) } } + return 0; +} + +static int +msdosfs_check_permitted(struct vnode *vp, struct denode *dep, mode_t mode, + kauth_cred_t cred) +{ + struct msdosfsmount *pmp = dep->de_pmp; + mode_t file_mode; + if ((dep->de_Attributes & ATTR_READONLY) == 0) - mode = S_IRWXU|S_IRWXG|S_IRWXO; + file_mode = S_IRWXU|S_IRWXG|S_IRWXO; else - mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; - return (vaccess(ap->a_vp->v_type, - mode & (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask), - pmp->pm_uid, pmp->pm_gid, ap->a_mode, ap->a_cred)); + file_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; + + return genfs_can_access(vp->v_type, + file_mode & (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask), + pmp->pm_uid, pmp->pm_gid, mode, cred); +} + +int +msdosfs_access(void *v) +{ + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct denode *dep = VTODE(vp); + int error; + + error = msdosfs_check_possible(vp, dep, ap->a_mode); + if (error) + return error; + + error = msdosfs_check_permitted(vp, dep, ap->a_mode, ap->a_cred); + + return error; } int -msdosfs_getattr(v) - void *v; +msdosfs_getattr(void *v) { struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; + kauth_cred_t a_cred; } */ *ap = v; struct denode *dep = VTODE(ap->a_vp); struct msdosfsmount *pmp = dep->de_pmp; struct vattr *vap = ap->a_vap; mode_t mode; - struct timespec ts; u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry); ino_t fileid; - TIMEVAL_TO_TIMESPEC(&time, &ts); - DETIMES(dep, &ts, &ts, &ts, pmp->pm_gmtoff); + fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED); + DETIMES(dep, NULL, NULL, NULL, pmp->pm_gmtoff); vap->va_fsid = dep->de_dev; /* * The following computation of the fileid must be the same as that @@ -335,29 +311,28 @@ msdosfs_getattr(v) vap->va_bytes = (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask; vap->va_type = ap->a_vp->v_type; + fstrans_done(ap->a_vp->v_mount); return (0); } int -msdosfs_setattr(v) - void *v; +msdosfs_setattr(void *v) { struct vop_setattr_args /* { struct vnode *a_vp; struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; + kauth_cred_t a_cred; } */ *ap = v; int error = 0, de_changed = 0; struct denode *dep = VTODE(ap->a_vp); struct msdosfsmount *pmp = dep->de_pmp; struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; + kauth_cred_t cred = ap->a_cred; #ifdef MSDOSFS_DEBUG - printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n", - ap->a_vp, vap, cred, ap->a_p); + printf("msdosfs_setattr(): vp %p, vap %p, cred %p\n", + ap->a_vp, vap, cred); #endif /* * Note we silently ignore uid or gid changes. @@ -370,11 +345,11 @@ msdosfs_setattr(v) (vap->va_gid != VNOVAL && vap->va_gid != pmp->pm_gid)) { #ifdef MSDOSFS_DEBUG printf("msdosfs_setattr(): returning EINVAL\n"); - printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %llx\n", + printf(" va_type %d, va_nlink %x, va_fsid %"PRIx64", va_fileid %llx\n", vap->va_type, vap->va_nlink, vap->va_fsid, (unsigned long long)vap->va_fileid); - printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n", - vap->va_blocksize, vap->va_rdev, (long long)vap->va_bytes, vap->va_gen); + printf(" va_blocksize %lx, va_rdev %"PRIx64", va_bytes %"PRIx64", va_gen %lx\n", + vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen); #endif return (EINVAL); } @@ -384,22 +359,26 @@ msdosfs_setattr(v) if (ap->a_vp->v_type == VDIR) return 0; + fstrans_start(vp->v_mount, FSTRANS_SHARED); if (vap->va_size != VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - error = detrunc(dep, (u_long)vap->va_size, 0, cred, ap->a_p); + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto bad; + } + error = detrunc(dep, (u_long)vap->va_size, 0, cred); if (error) - return (error); + goto bad; de_changed = 1; } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if (cred->cr_uid != pmp->pm_uid && - (error = suser(cred, &ap->a_p->p_acflag)) && - ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || - (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p)))) - return (error); + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto bad; + } + error = genfs_can_chtimes(ap->a_vp, vap->va_vaflags, + pmp->pm_uid, cred); + if (error) + goto bad; if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 && vap->va_atime.tv_sec != VNOVAL) unix2dostime(&vap->va_atime, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL); @@ -415,11 +394,14 @@ msdosfs_setattr(v) * attribute. */ if (vap->va_mode != (mode_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if (cred->cr_uid != pmp->pm_uid && - (error = suser(cred, &ap->a_p->p_acflag))) - return (error); + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto bad; + } + if (kauth_cred_geteuid(cred) != pmp->pm_uid && + (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, + NULL))) + goto bad; /* We ignore the read and execute bits. */ if (vap->va_mode & S_IWUSR) dep->de_Attributes &= ~ATTR_READONLY; @@ -432,11 +414,14 @@ msdosfs_setattr(v) * Allow the `archived' bit to be toggled. */ if (vap->va_flags != VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if (cred->cr_uid != pmp->pm_uid && - (error = suser(cred, &ap->a_p->p_acflag))) - return (error); + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto bad; + } + if (kauth_cred_geteuid(cred) != pmp->pm_uid && + (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, + NULL))) + goto bad; if (vap->va_flags & SF_ARCHIVED) dep->de_Attributes &= ~ATTR_ARCHIVE; else @@ -447,28 +432,31 @@ msdosfs_setattr(v) if (de_changed) { VN_KNOTE(vp, NOTE_ATTRIB); - return (deupdat(dep, 1)); - } else - return (0); + error = deupdat(dep, 1); + if (error) + goto bad; + } + +bad: + fstrans_done(vp->v_mount); + return error; } int -msdosfs_read(v) - void *v; +msdosfs_read(void *v) { struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; - struct ucred *a_cred; + kauth_cred_t a_cred; } */ *ap = v; - int error = 0, flags; + int error = 0; int64_t diff; int blsize; long n; long on; daddr_t lbn; - void *win; vsize_t bytelen; struct buf *bp; struct vnode *vp = ap->a_vp; @@ -487,18 +475,18 @@ msdosfs_read(v) if (uio->uio_offset >= dep->de_FileSize) return (0); + fstrans_start(vp->v_mount, FSTRANS_SHARED); if (vp->v_type == VREG) { + const int advice = IO_ADV_DECODE(ap->a_ioflag); + while (uio->uio_resid > 0) { bytelen = MIN(dep->de_FileSize - uio->uio_offset, uio->uio_resid); if (bytelen == 0) break; - win = ubc_alloc(&vp->v_uobj, uio->uio_offset, - &bytelen, UBC_READ); - error = uiomove(win, bytelen, uio); - flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; - ubc_release(win, flags); + error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, + UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); if (error) break; } @@ -518,29 +506,32 @@ msdosfs_read(v) if (diff < n) n = (long) diff; - /* convert cluster # to block # */ + /* convert cluster # to sector # */ error = pcbmap(dep, lbn, &lbn, 0, &blsize); if (error) - return (error); + goto bad; /* * If we are operating on a directory file then be sure to * do i/o with the vnode for the filesystem instead of the * vnode for the directory. */ - error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp); + error = bread(pmp->pm_devvp, de_bn2kb(pmp, lbn), blsize, + NOCRED, 0, &bp); n = MIN(n, pmp->pm_bpcluster - bp->b_resid); if (error) { - brelse(bp); - return (error); + brelse(bp, 0); + goto bad; } - error = uiomove(bp->b_data + on, (int) n, uio); - brelse(bp); + error = uiomove((char *)bp->b_data + on, (int) n, uio); + brelse(bp, 0); } while (error == 0 && uio->uio_resid > 0 && n != 0); out: if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) error = deupdat(dep, 1); +bad: + fstrans_done(vp->v_mount); return (error); } @@ -548,30 +539,28 @@ out: * Write data to a file or directory. */ int -msdosfs_write(v) - void *v; +msdosfs_write(void *v) { struct vop_write_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; - struct ucred *a_cred; + kauth_cred_t a_cred; } */ *ap = v; - int resid, flags, extended = 0; + int resid, extended = 0; int error = 0; int ioflag = ap->a_ioflag; u_long osize; u_long count; - void *win; vsize_t bytelen; off_t oldoff; + size_t rem; struct uio *uio = ap->a_uio; - struct proc *p = uio->uio_procp; struct vnode *vp = ap->a_vp; struct denode *dep = VTODE(vp); struct msdosfsmount *pmp = dep->de_pmp; - struct ucred *cred = ap->a_cred; - boolean_t async; + kauth_cred_t cred = ap->a_cred; + bool async; #ifdef MSDOSFS_DEBUG printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n", @@ -601,16 +590,7 @@ msdosfs_write(v) if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX) return (EFBIG); - /* - * If they've exceeded their filesize limit, tell them about it. - */ - if (p && - ((uio->uio_offset + uio->uio_resid) > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { - psignal(p, SIGXFSZ); - return (EFBIG); - } - + fstrans_start(vp->v_mount, FSTRANS_SHARED); /* * If the offset we are starting the write at is beyond the end of * the file, then they've done a seek. Unix filesystems allow @@ -618,8 +598,10 @@ msdosfs_write(v) * with zeroed blocks. */ if (uio->uio_offset > dep->de_FileSize) { - if ((error = deextend(dep, uio->uio_offset, cred)) != 0) + if ((error = deextend(dep, uio->uio_offset, cred)) != 0) { + fstrans_done(vp->v_mount); return (error); + } } /* @@ -636,14 +618,16 @@ msdosfs_write(v) if (uio->uio_offset + resid > osize) { count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize); - if ((error = extendfile(dep, count, NULL, NULL, 0)) && - (error != ENOSPC || (ioflag & IO_UNIT))) + if ((error = extendfile(dep, count, NULL, NULL, 0))) goto errexit; - } - if (dep->de_FileSize < uio->uio_offset + resid) { dep->de_FileSize = uio->uio_offset + resid; - uvm_vnp_setsize(vp, dep->de_FileSize); + /* hint uvm to not read in extended part */ + uvm_vnp_setwritesize(vp, dep->de_FileSize); + /* zero out the remainder of the last page */ + rem = round_page(dep->de_FileSize) - dep->de_FileSize; + if (rem > 0) + uvm_vnp_zerorange(vp, (off_t)dep->de_FileSize, rem); extended = 1; } @@ -651,13 +635,10 @@ msdosfs_write(v) oldoff = uio->uio_offset; bytelen = uio->uio_resid; - win = ubc_alloc(&vp->v_uobj, oldoff, &bytelen, UBC_WRITE); - error = uiomove(win, bytelen, uio); - flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; - ubc_release(win, flags); - if (error) { + error = ubc_uiomove(&vp->v_uobj, uio, bytelen, + IO_ADV_DECODE(ioflag), UBC_WRITE | UBC_UNMAP_FLAG(vp)); + if (error) break; - } /* * flush what we just wrote if necessary. @@ -665,13 +646,16 @@ msdosfs_write(v) */ if (!async && oldoff >> 16 != uio->uio_offset >> 16) { - simple_lock(&vp->v_interlock); + mutex_enter(vp->v_interlock); error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, (uio->uio_offset >> 16) << 16, PGO_CLEANIT); } } while (error == 0 && uio->uio_resid > 0); + + /* set final size */ + uvm_vnp_setsize(vp, dep->de_FileSize); if (error == 0 && ioflag & IO_SYNC) { - simple_lock(&vp->v_interlock); + mutex_enter(vp->v_interlock); error = VOP_PUTPAGES(vp, trunc_page(oldoff), round_page(oldoff + bytelen), PGO_CLEANIT | PGO_SYNCIO); } @@ -685,38 +669,29 @@ errexit: if (resid > uio->uio_resid) VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); if (error) { - detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL); + detrunc(dep, osize, ioflag & IO_SYNC, NOCRED); uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } else if ((ioflag & IO_SYNC) == IO_SYNC) error = deupdat(dep, 1); + fstrans_done(vp->v_mount); KASSERT(vp->v_size == dep->de_FileSize); return (error); } int -msdosfs_update(v) - void *v; +msdosfs_update(struct vnode *vp, const struct timespec *acc, + const struct timespec *mod, int flags) { - struct vop_update_args /* { - struct vnode *a_vp; - struct timespec *a_access; - struct timespec *a_modify; - int a_flags; - } */ *ap = v; struct buf *bp; struct direntry *dirp; struct denode *dep; int error; - struct timespec ts; - if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + if (vp->v_mount->mnt_flag & MNT_RDONLY) return (0); - dep = VTODE(ap->a_vp); - TIMEVAL_TO_TIMESPEC(&time, &ts); - DETIMES(dep, - ap->a_access ? ap->a_access : &ts, - ap->a_modify ? ap->a_modify : &ts, &ts, dep->de_pmp->pm_gmtoff); + dep = VTODE(vp); + DETIMES(dep, acc, mod, NULL, dep->de_pmp->pm_gmtoff); if ((dep->de_flag & DE_MODIFIED) == 0) return (0); dep->de_flag &= ~DE_MODIFIED; @@ -728,7 +703,7 @@ msdosfs_update(v) if (error) return (error); DE_EXTERNALIZE(dirp, dep); - if (ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) + if (flags & (UPDATE_WAIT|UPDATE_DIROP)) return (bwrite(bp)); else { bdwrite(bp); @@ -743,8 +718,7 @@ msdosfs_update(v) * could just do a sync if they try an fsync on a directory file. */ int -msdosfs_remove(v) - void *v; +msdosfs_remove(void *v) { struct vop_remove_args /* { struct vnode *a_dvp; @@ -755,6 +729,7 @@ msdosfs_remove(v) struct denode *ddep = VTODE(ap->a_dvp); int error; + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); if (ap->a_vp->v_type == VDIR) error = EPERM; else @@ -771,30 +746,11 @@ msdosfs_remove(v) vput(ap->a_vp); /* causes msdosfs_inactive() to be called * via vrele() */ vput(ap->a_dvp); + fstrans_done(ap->a_dvp->v_mount); return (error); } /* - * DOS filesystems don't know what links are. But since we already called - * msdosfs_lookup() with create and lockparent, the parent is locked so we - * have to free it before we return the error. - */ -int -msdosfs_link(v) - void *v; -{ - struct vop_link_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; - } */ *ap = v; - - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - return (EOPNOTSUPP); -} - -/* * Renames on files require moving the denode to a new hash queue since the * denode's location is used to compute which hash queue to put the file * in. Unless it is a rename in place. For example "mv a b". @@ -846,10 +802,12 @@ msdosfs_link(v) * I'm not sure how the memory containing the pathnames pointed at by the * componentname structures is freed, there may be some memory bleeding * for each rename done. + * + * --More-- Notes: + * This routine needs help. badly. */ int -msdosfs_rename(v) - void *v; +msdosfs_rename(void *v) { struct vop_rename_args /* { struct vnode *a_fdvp; @@ -865,9 +823,8 @@ msdosfs_rename(v) struct vnode *fdvp = ap->a_fdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; - struct proc *p = tcnp->cn_proc; struct denode *ip, *xp, *dp, *zp; - u_char toname[11], oldname[11]; + u_char toname[12], oldname[12]; u_long from_diroffset, to_diroffset; u_char to_count; int doingdirectory = 0, newparent = 0; @@ -877,15 +834,9 @@ msdosfs_rename(v) struct msdosfsmount *pmp; struct direntry *dotdotp; struct buf *bp; - int fdvp_dorele = 0; pmp = VFSTOMSDOSFS(fdvp->v_mount); -#ifdef DIAGNOSTIC - if ((tcnp->cn_flags & HASBUF) == 0 || - (fcnp->cn_flags & HASBUF) == 0) - panic("msdosfs_rename: no name"); -#endif /* * Check for cross-device rename. */ @@ -914,7 +865,10 @@ abortit: goto abortit; } - /* */ + /* + * XXX: This can deadlock since we hold tdvp/tvp locked. + * But I'm not going to fix it now. + */ if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) goto abortit; dp = VTODE(fdvp); @@ -935,7 +889,7 @@ abortit: (fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT) || (ip->de_flag & DE_RENAME)) { - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); error = EINVAL; goto abortit; } @@ -944,6 +898,7 @@ abortit: } VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ + fstrans_start(fdvp->v_mount, FSTRANS_SHARED); /* * When the target exists, both the directory * and target vnodes are returned locked. @@ -966,26 +921,31 @@ abortit: * to namei, as the parent directory is unlocked by the * call to doscheckpath(). */ - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, p); - VOP_UNLOCK(fvp, 0); + error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred); + VOP_UNLOCK(fvp); if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster) newparent = 1; - vrele(fdvp); + if (doingdirectory && newparent) { if (error) /* write access check above */ - goto bad; + goto tdvpbad; if (xp != NULL) vput(tvp); + tvp = NULL; /* - * doscheckpath() vput()'s dp, - * so we have to do a relookup afterwards + * doscheckpath() vput()'s tdvp (dp == VTODE(tdvp)), + * so we have to get an extra ref to it first, and + * because it's been unlocked we need to do a relookup + * afterwards in case tvp has changed. */ + vref(tdvp); if ((error = doscheckpath(ip, dp)) != 0) - goto out; - if ((tcnp->cn_flags & SAVESTART) == 0) - panic("msdosfs_rename: lost to startdir"); - if ((error = relookup(tdvp, &tvp, tcnp)) != 0) - goto out; + goto bad; + vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); + if ((error = relookup(tdvp, &tvp, tcnp, 0)) != 0) { + VOP_UNLOCK(tdvp); + goto bad; + } dp = VTODE(tdvp); xp = tvp ? VTODE(tvp) : NULL; } @@ -999,22 +959,23 @@ abortit: if (xp->de_Attributes & ATTR_DIRECTORY) { if (!dosdirempty(xp)) { error = ENOTEMPTY; - goto bad; + goto tdvpbad; } if (!doingdirectory) { error = ENOTDIR; - goto bad; + goto tdvpbad; } } else if (doingdirectory) { error = EISDIR; - goto bad; + goto tdvpbad; } if ((error = removede(dp, xp)) != 0) - goto bad; + goto tdvpbad; VN_KNOTE(tdvp, NOTE_WRITE); VN_KNOTE(tvp, NOTE_DELETE); cache_purge(tvp); vput(tvp); + tvp = NULL; xp = NULL; } @@ -1023,8 +984,10 @@ abortit: * into the denode and directory entry for the destination * file/directory. */ - if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) + if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) { + fstrans_done(fdvp->v_mount); goto abortit; + } /* * Since from wasn't locked at various places above, @@ -1032,24 +995,28 @@ abortit: */ fcnp->cn_flags &= ~MODMASK; fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; - if ((fcnp->cn_flags & SAVESTART) == 0) - panic("msdosfs_rename: lost from startdir"); - if (!newparent) - VOP_UNLOCK(tdvp, 0); - (void) relookup(fdvp, &fvp, fcnp); + VOP_UNLOCK(tdvp); + vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); + if ((error = relookup(fdvp, &fvp, fcnp, 0))) { + VOP_UNLOCK(fdvp); + vrele(ap->a_fvp); + vrele(tdvp); + fstrans_done(fdvp->v_mount); + return (error); + } if (fvp == NULL) { /* * From name has disappeared. */ if (doingdirectory) panic("rename: lost dir entry"); + vput(fdvp); vrele(ap->a_fvp); - if (newparent) - VOP_UNLOCK(tdvp, 0); vrele(tdvp); + fstrans_done(fdvp->v_mount); return 0; } - fdvp_dorele = 1; + VOP_UNLOCK(fdvp); xp = VTODE(fvp); zp = VTODE(fdvp); from_diroffset = zp->de_fndoffset; @@ -1066,9 +1033,6 @@ abortit: if (doingdirectory) panic("rename: lost dir entry"); vrele(ap->a_fvp); - VOP_UNLOCK(fvp, 0); - if (newparent) - VOP_UNLOCK(fdvp, 0); xp = NULL; } else { vrele(fvp); @@ -1089,18 +1053,14 @@ abortit: error = createde(ip, dp, (struct denode **)0, tcnp); if (error) { memcpy(ip->de_Name, oldname, 11); - if (newparent) - VOP_UNLOCK(fdvp, 0); - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); goto bad; } ip->de_refcnt++; zp->de_fndoffset = from_diroffset; if ((error = removede(zp, ip)) != 0) { /* XXX should really panic here, fs is corrupt */ - if (newparent) - VOP_UNLOCK(fdvp, 0); - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); goto bad; } cache_purge(fvp); @@ -1109,9 +1069,7 @@ abortit: &ip->de_dirclust, 0); if (error) { /* XXX should really panic here, fs is corrupt */ - if (newparent) - VOP_UNLOCK(fdvp, 0); - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); goto bad; } ip->de_diroffset = to_diroffset; @@ -1119,8 +1077,6 @@ abortit: ip->de_diroffset &= pmp->pm_crbomask; } reinsert(ip); - if (newparent) - VOP_UNLOCK(fdvp, 0); } /* @@ -1134,12 +1090,12 @@ abortit: panic("msdosfs_rename: updating .. in root directory?"); } else bn = cntobn(pmp, cn); - error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, - NOCRED, &bp); + error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), + pmp->pm_bpcluster, NOCRED, B_MODIFY, &bp); if (error) { /* XXX should really panic here, fs is corrupt */ - brelse(bp); - VOP_UNLOCK(fvp, 0); + brelse(bp, 0); + VOP_UNLOCK(fvp); goto bad; } dotdotp = (struct direntry *)bp->b_data + 1; @@ -1147,27 +1103,32 @@ abortit: if (FAT32(pmp)) { putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16); + } else { + putushort(dotdotp->deHighClust, 0); } if ((error = bwrite(bp)) != 0) { /* XXX should really panic here, fs is corrupt */ - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); goto bad; } } VN_KNOTE(fvp, NOTE_RENAME); - VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(fvp); bad: - if (xp) + if (tvp) vput(tvp); - vput(tdvp); -out: + vrele(tdvp); ip->de_flag &= ~DE_RENAME; - if (fdvp_dorele) - vrele(fdvp); + vrele(fdvp); vrele(fvp); + fstrans_done(fdvp->v_mount); return (error); + /* XXX: uuuh */ +tdvpbad: + VOP_UNLOCK(tdvp); + goto bad; } static const struct { @@ -1197,8 +1158,7 @@ static const struct { }; int -msdosfs_mkdir(v) - void *v; +msdosfs_mkdir(void *v) { struct vop_mkdir_args /* { struct vnode *a_dvp; @@ -1213,12 +1173,13 @@ msdosfs_mkdir(v) int error; int bn; u_long newcluster, pcl; + daddr_t lbn; struct direntry *denp; struct msdosfsmount *pmp = pdep->de_pmp; struct buf *bp; - struct timespec ts; int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not @@ -1240,8 +1201,7 @@ msdosfs_mkdir(v) memset(&ndirent, 0, sizeof(ndirent)); ndirent.de_pmp = pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; - TIMEVAL_TO_TIMESPEC(&time, &ts); - DETIMES(&ndirent, &ts, &ts, &ts, pmp->pm_gmtoff); + DETIMES(&ndirent, NULL, NULL, NULL, pmp->pm_gmtoff); /* * Now fill the cluster with the "." and ".." entries. And write @@ -1249,8 +1209,9 @@ msdosfs_mkdir(v) * directory to be pointing at if there were a crash. */ bn = cntobn(pmp, newcluster); + lbn = de_bn2kb(pmp, bn); /* always succeeds */ - bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0); + bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0); memset(bp->b_data, 0, pmp->pm_bpcluster); memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); denp = (struct direntry *)bp->b_data; @@ -1274,6 +1235,9 @@ msdosfs_mkdir(v) if (FAT32(pmp)) { putushort(denp[0].deHighClust, newcluster >> 16); putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); + } else { + putushort(denp[0].deHighClust, 0); + putushort(denp[1].deHighClust, 0); } if (async) @@ -1286,10 +1250,6 @@ msdosfs_mkdir(v) * cluster. This will be written to an empty slot in the parent * directory. */ -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & HASBUF) == 0) - panic("msdosfs_mkdir: no name"); -#endif if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0) goto bad; @@ -1300,24 +1260,22 @@ msdosfs_mkdir(v) ndirent.de_devvp = pdep->de_devvp; if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) goto bad; - if ((cnp->cn_flags & SAVESTART) == 0) - PNBUF_PUT(cnp->cn_pnbuf); VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK); vput(ap->a_dvp); *ap->a_vpp = DETOV(dep); + fstrans_done(ap->a_dvp->v_mount); return (0); bad: clusterfree(pmp, newcluster, NULL); bad2: - PNBUF_PUT(cnp->cn_pnbuf); vput(ap->a_dvp); + fstrans_done(ap->a_dvp->v_mount); return (error); } int -msdosfs_rmdir(v) - void *v; +msdosfs_rmdir(void *v) { struct vop_rmdir_args /* { struct vnode *a_dvp; @@ -1340,6 +1298,7 @@ msdosfs_rmdir(v) vput(vp); return (EINVAL); } + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); /* * Verify the directory is empty (and valid). * (Rmdir ".." won't be valid since @@ -1374,44 +1333,24 @@ msdosfs_rmdir(v) /* * Truncate the directory that is being deleted. */ - error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc); + error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred); cache_purge(vp); out: VN_KNOTE(vp, NOTE_DELETE); if (dvp) vput(dvp); vput(vp); + fstrans_done(ap->a_dvp->v_mount); return (error); } -/* - * DOS filesystems don't know what symlinks are. - */ -int -msdosfs_symlink(v) - void *v; -{ - struct vop_symlink_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - char *a_target; - } */ *ap = v; - - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - return (EOPNOTSUPP); -} - int -msdosfs_readdir(v) - void *v; +msdosfs_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; - struct ucred *a_cred; + kauth_cred_t a_cred; int *a_eofflag; off_t **a_cookies; int *a_ncookies; @@ -1432,7 +1371,7 @@ msdosfs_readdir(v) struct denode *dep = VTODE(ap->a_vp); struct msdosfsmount *pmp = dep->de_pmp; struct direntry *dentp; - struct dirent dirbuf; + struct dirent *dirbuf; struct uio *uio = ap->a_uio; off_t *cookies = NULL; int ncookies = 0, nc = 0; @@ -1454,11 +1393,6 @@ msdosfs_readdir(v) return (ENOTDIR); /* - * To be safe, initialize dirbuf - */ - memset(dirbuf.d_name, 0, sizeof(dirbuf.d_name)); - - /* * If the user buffer is smaller than the size of one dos directory * entry or the file offset is not a multiple of the size of a * directory entry, then we fail the read. @@ -1471,9 +1405,14 @@ msdosfs_readdir(v) lost = uio->uio_resid - count; uio->uio_resid = count; uio_off = uio->uio_offset; + + fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED); + + /* Allocate a temporary dirent buffer. */ + dirbuf = malloc(sizeof(struct dirent), M_MSDOSFSTMP, M_WAITOK | M_ZERO); if (ap->a_ncookies) { - nc = uio->uio_resid / 16; + nc = uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); cookies = malloc(nc * sizeof (off_t), M_TEMP, M_WAITOK); *ap->a_cookies = cookies; } @@ -1490,37 +1429,36 @@ msdosfs_readdir(v) if (dep->de_StartCluster == MSDOSFSROOT || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) { #if 0 - printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n", - offset); + printf("msdosfs_readdir(): going after . or .. in root dir, " + "offset %" PRIu64 "\n", offset); #endif bias = 2 * sizeof(struct direntry); if (offset < bias) { for (n = (int)offset / sizeof(struct direntry); n < 2; n++) { if (FAT32(pmp)) - dirbuf.d_fileno = cntobn(pmp, + dirbuf->d_fileno = cntobn(pmp, (ino_t)pmp->pm_rootdirblk) * dirsperblk; else - dirbuf.d_fileno = 1; - dirbuf.d_type = DT_DIR; + dirbuf->d_fileno = 1; + dirbuf->d_type = DT_DIR; switch (n) { case 0: - dirbuf.d_namlen = 1; - strlcpy(dirbuf.d_name, ".", - sizeof(dirbuf.d_name)); + dirbuf->d_namlen = 1; + strlcpy(dirbuf->d_name, ".", + sizeof(dirbuf->d_name)); break; case 1: - dirbuf.d_namlen = 2; - strlcpy(dirbuf.d_name, "..", - sizeof(dirbuf.d_name)); + dirbuf->d_namlen = 2; + strlcpy(dirbuf->d_name, "..", + sizeof(dirbuf->d_name)); break; } - dirbuf.d_reclen = _DIRENT_SIZE(&dirbuf); - if (uio->uio_resid < dirbuf.d_reclen) + dirbuf->d_reclen = _DIRENT_SIZE(dirbuf); + if (uio->uio_resid < dirbuf->d_reclen) goto out; - error = uiomove(&dirbuf, - dirbuf.d_reclen, uio); + error = uiomove(dirbuf, dirbuf->d_reclen, uio); if (error) goto out; offset += sizeof(struct direntry); @@ -1545,10 +1483,11 @@ msdosfs_readdir(v) n = MIN(n, diff); if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0) break; - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, + NOCRED, 0, &bp); if (error) { - brelse(bp); - return (error); + brelse(bp, 0); + goto bad; } n = MIN(n, blsize - bp->b_resid); @@ -1556,8 +1495,8 @@ msdosfs_readdir(v) * Convert from dos directory entries to fs-independent * directory entries. */ - for (dentp = (struct direntry *)(bp->b_data + on); - (char *)dentp < bp->b_data + on + n; + for (dentp = (struct direntry *)((char *)bp->b_data + on); + (char *)dentp < (char *)bp->b_data + on + n; dentp++, offset += sizeof(struct direntry)) { #if 0 @@ -1568,7 +1507,7 @@ msdosfs_readdir(v) * If this is an unused entry, we can stop. */ if (dentp->deName[0] == SLOT_EMPTY) { - brelse(bp); + brelse(bp, 0); goto out; } /* @@ -1585,7 +1524,8 @@ msdosfs_readdir(v) if (dentp->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; - chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum); + chksum = win2unixfn((struct winentry *)dentp, + dirbuf, chksum); continue; } @@ -1615,28 +1555,28 @@ msdosfs_readdir(v) fileno = 1; else fileno = cntobn(pmp, fileno) * dirsperblk; - dirbuf.d_fileno = fileno; - dirbuf.d_type = DT_DIR; + dirbuf->d_fileno = fileno; + dirbuf->d_type = DT_DIR; } else { - dirbuf.d_fileno = offset / sizeof(struct direntry); - dirbuf.d_type = DT_REG; + dirbuf->d_fileno = + offset / sizeof(struct direntry); + dirbuf->d_type = DT_REG; } if (chksum != winChksum(dentp->deName)) - dirbuf.d_namlen = dos2unixfn(dentp->deName, - (u_char *)dirbuf.d_name, + dirbuf->d_namlen = dos2unixfn(dentp->deName, + (u_char *)dirbuf->d_name, pmp->pm_flags & MSDOSFSMNT_SHORTNAME); else - dirbuf.d_name[dirbuf.d_namlen] = 0; + dirbuf->d_name[dirbuf->d_namlen] = 0; chksum = -1; - dirbuf.d_reclen = _DIRENT_SIZE(&dirbuf); - if (uio->uio_resid < dirbuf.d_reclen) { - brelse(bp); + dirbuf->d_reclen = _DIRENT_SIZE(dirbuf); + if (uio->uio_resid < dirbuf->d_reclen) { + brelse(bp, 0); goto out; } - error = uiomove(&dirbuf, - dirbuf.d_reclen, uio); + error = uiomove(dirbuf, dirbuf->d_reclen, uio); if (error) { - brelse(bp); + brelse(bp, 0); goto out; } uio_off = offset + sizeof(struct direntry); @@ -1644,12 +1584,12 @@ msdosfs_readdir(v) *cookies++ = offset + sizeof(struct direntry); ncookies++; if (ncookies >= nc) { - brelse(bp); + brelse(bp, 0); goto out; } } } - brelse(bp); + brelse(bp, 0); } out: @@ -1668,25 +1608,11 @@ out: } else *ap->a_ncookies = ncookies; } - return (error); -} -/* - * DOS filesystems don't know what symlinks are. - */ -int -msdosfs_readlink(v) - void *v; -{ -#if 0 - struct vop_readlink_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - } */ *ap; -#endif - - return (EINVAL); +bad: + free(dirbuf, M_MSDOSFSTMP); + fstrans_done(ap->a_vp->v_mount); + return (error); } /* @@ -1697,8 +1623,7 @@ msdosfs_readlink(v) * bnp - address of where to return the filesystem relative block number */ int -msdosfs_bmap(v) - void *v; +msdosfs_bmap(void *v) { struct vop_bmap_args /* { struct vnode *a_vp; @@ -1708,38 +1633,46 @@ msdosfs_bmap(v) int *a_runp; } */ *ap = v; struct denode *dep = VTODE(ap->a_vp); + int run, maxrun; + daddr_t runbn; + int status; if (ap->a_vpp != NULL) *ap->a_vpp = dep->de_devvp; if (ap->a_bnp == NULL) return (0); - if (ap->a_runp) { - /* - * Sequential clusters should be counted here. - */ - *ap->a_runp = 0; - } - return (pcbmap(dep, ap->a_bn, ap->a_bnp, 0, 0)); -} + status = pcbmap(dep, ap->a_bn, ap->a_bnp, 0, 0); -int -msdosfs_reallocblks(v) - void *v; -{ -#if 0 - struct vop_reallocblks_args /* { - struct vnode *a_vp; - struct cluster_save *a_buflist; - } */ *ap = v; -#endif + /* + * From FreeBSD: + * A little kludgy, but we loop calling pcbmap until we + * reach the end of the contiguous piece, or reach MAXPHYS. + * Since it reduces disk I/Os, the "wasted" CPU is put to + * good use (4 to 5 fold sequential read I/O improvement on USB + * drives). + */ + if (ap->a_runp != NULL) { + /* taken from ufs_bmap */ + maxrun = ulmin(MAXPHYS / dep->de_pmp->pm_bpcluster - 1, + dep->de_pmp->pm_maxcluster - ap->a_bn); + for (run = 1; run <= maxrun; run++) { + if (pcbmap(dep, ap->a_bn + run, &runbn, NULL, NULL) + != 0 || runbn != + *ap->a_bnp + de_cn2bn(dep->de_pmp, run)) + break; + } + *ap->a_runp = run - 1; + } - /* Currently no support for clustering */ /* XXX */ - return (ENOSPC); + /* + * We need to scale *ap->a_bnp by sector_size/DEV_BSIZE + */ + *ap->a_bnp = de_bn2kb(dep->de_pmp, *ap->a_bnp); + return status; } int -msdosfs_strategy(v) - void *v; +msdosfs_strategy(void *v) { struct vop_strategy_args /* { struct vnode *a_vp; @@ -1765,6 +1698,8 @@ msdosfs_strategy(v) bp->b_blkno = -1; if (bp->b_blkno == -1) clrbuf(bp); + else + bp->b_blkno = de_bn2kb(dep->de_pmp, bp->b_blkno); } if (bp->b_blkno == -1) { biodone(bp); @@ -1781,8 +1716,7 @@ msdosfs_strategy(v) } int -msdosfs_print(v) - void *v; +msdosfs_print(void *v) { struct vop_print_args /* { struct vnode *vp; @@ -1792,15 +1726,14 @@ msdosfs_print(v) printf( "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ", dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset); - printf(" dev %d, %d ", major(dep->de_dev), minor(dep->de_dev)); - lockmgr_printinfo(&ap->a_vp->v_lock); + printf(" dev %llu, %llu ", (unsigned long long)major(dep->de_dev), + (unsigned long long)minor(dep->de_dev)); printf("\n"); return (0); } int -msdosfs_advlock(v) - void *v; +msdosfs_advlock(void *v) { struct vop_advlock_args /* { struct vnode *a_vp; @@ -1815,8 +1748,7 @@ msdosfs_advlock(v) } int -msdosfs_pathconf(v) - void *v; +msdosfs_pathconf(void *v) { struct vop_pathconf_args /* { struct vnode *a_vp; @@ -1852,21 +1784,89 @@ msdosfs_pathconf(v) /* NOTREACHED */ } +int +msdosfs_fsync(void *v) +{ + struct vop_fsync_args /* { + struct vnode *a_vp; + kauth_cred_t a_cred; + int a_flags; + off_t offlo; + off_t offhi; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int wait; + int error; + + fstrans_start(vp->v_mount, FSTRANS_LAZY); + wait = (ap->a_flags & FSYNC_WAIT) != 0; + error = vflushbuf(vp, wait); + if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0) + error = msdosfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); + + if (error == 0 && ap->a_flags & FSYNC_CACHE) { + struct denode *dep = VTODE(vp); + struct vnode *devvp = dep->de_devvp; + + int l = 0; + error = VOP_IOCTL(devvp, DIOCCACHESYNC, &l, FWRITE, + curlwp->l_cred); + } + fstrans_done(vp->v_mount); + + return (error); +} + +void +msdosfs_detimes(struct denode *dep, const struct timespec *acc, + const struct timespec *mod, const struct timespec *cre, int gmtoff) +{ + struct timespec *ts = NULL, tsb; + + KASSERT(dep->de_flag & (DE_UPDATE | DE_CREATE | DE_ACCESS)); + /* XXX just call getnanotime early and use result if needed? */ + dep->de_flag |= DE_MODIFIED; + if (dep->de_flag & DE_UPDATE) { + if (mod == NULL) { + getnanotime(&tsb); + mod = ts = &tsb; + } + unix2dostime(mod, gmtoff, &dep->de_MDate, &dep->de_MTime, NULL); + dep->de_Attributes |= ATTR_ARCHIVE; + } + if ((dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0) { + if (dep->de_flag & DE_ACCESS) { + if (acc == NULL) + acc = ts == NULL ? + (getnanotime(&tsb), ts = &tsb) : ts; + unix2dostime(acc, gmtoff, &dep->de_ADate, NULL, NULL); + } + if (dep->de_flag & DE_CREATE) { + if (cre == NULL) + cre = ts == NULL ? + (getnanotime(&tsb), ts = &tsb) : ts; + unix2dostime(cre, gmtoff, &dep->de_CDate, + &dep->de_CTime, &dep->de_CHun); + } + } + + dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); +} + /* Global vfs data structures for msdosfs */ int (**msdosfs_vnodeop_p)(void *); const struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, msdosfs_lookup }, /* lookup */ { &vop_create_desc, msdosfs_create }, /* create */ - { &vop_mknod_desc, msdosfs_mknod }, /* mknod */ - { &vop_open_desc, msdosfs_open }, /* open */ + { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ + { &vop_open_desc, genfs_nullop }, /* open */ { &vop_close_desc, msdosfs_close }, /* close */ { &vop_access_desc, msdosfs_access }, /* access */ { &vop_getattr_desc, msdosfs_getattr }, /* getattr */ { &vop_setattr_desc, msdosfs_setattr }, /* setattr */ { &vop_read_desc, msdosfs_read }, /* read */ { &vop_write_desc, msdosfs_write }, /* write */ - { &vop_lease_desc, msdosfs_lease_check }, /* lease */ { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ { &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */ { &vop_poll_desc, msdosfs_poll }, /* poll */ @@ -1876,13 +1876,13 @@ const struct vnodeopv_entry_desc msdosfs { &vop_fsync_desc, msdosfs_fsync }, /* fsync */ { &vop_seek_desc, msdosfs_seek }, /* seek */ { &vop_remove_desc, msdosfs_remove }, /* remove */ - { &vop_link_desc, msdosfs_link }, /* link */ + { &vop_link_desc, genfs_eopnotsupp }, /* link */ { &vop_rename_desc, msdosfs_rename }, /* rename */ { &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */ { &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */ - { &vop_symlink_desc, msdosfs_symlink }, /* symlink */ + { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */ { &vop_readdir_desc, msdosfs_readdir }, /* readdir */ - { &vop_readlink_desc, msdosfs_readlink }, /* readlink */ + { &vop_readlink_desc, genfs_einval }, /* readlink */ { &vop_abortop_desc, msdosfs_abortop }, /* abortop */ { &vop_inactive_desc, msdosfs_inactive }, /* inactive */ { &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */ @@ -1894,8 +1894,6 @@ const struct vnodeopv_entry_desc msdosfs { &vop_islocked_desc, genfs_islocked }, /* islocked */ { &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */ { &vop_advlock_desc, msdosfs_advlock }, /* advlock */ - { &vop_reallocblks_desc, msdosfs_reallocblks }, /* reallocblks */ - { &vop_update_desc, msdosfs_update }, /* update */ { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ { &vop_getpages_desc, genfs_getpages }, /* getpages */ { &vop_putpages_desc, genfs_putpages }, /* putpages */