Page MenuHomeFreeBSD

D33721.id101088.diff
No OneTemporary

D33721.id101088.diff

diff --git a/sys/fs/msdosfs/fat.h b/sys/fs/msdosfs/fat.h
--- a/sys/fs/msdosfs/fat.h
+++ b/sys/fs/msdosfs/fat.h
@@ -97,7 +97,7 @@
#define DE_CLEAR 1 /* Zero out the blocks allocated */
int pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int* sp);
-int clusterfree(struct msdosfsmount *pmp, u_long cn, u_long *oldcnp);
+void clusterfree(struct msdosfsmount *pmp, u_long cn);
int clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got);
int fatentry(int function, struct msdosfsmount *pmp, u_long cluster, u_long *oldcontents, u_long newcontents);
int freeclusterchain(struct msdosfsmount *pmp, u_long startchain);
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -142,9 +142,24 @@
return (error);
if (nvp != NULL) {
*depp = VTODE(nvp);
- KASSERT((*depp)->de_dirclust == dirclust, ("wrong dirclust"));
- KASSERT((*depp)->de_diroffset == diroffset, ("wrong diroffset"));
+ if ((*depp)->de_dirclust != dirclust) {
+ printf("%s: wrong dir cluster %lu %lu\n",
+ pmp->pm_mountp->mnt_stat.f_mntonname,
+ (*depp)->de_dirclust, dirclust);
+ goto badoff;
+ }
+ if ((*depp)->de_diroffset != diroffset) {
+ printf("%s: wrong dir offset %lu %lu\n",
+ pmp->pm_mountp->mnt_stat.f_mntonname,
+ (*depp)->de_diroffset, diroffset);
+ goto badoff;
+ }
return (0);
+badoff:
+ vgone(nvp);
+ vput(nvp);
+ msdosfs_integrity_error(pmp);
+ return (EBADF);
}
ldep = malloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK | M_ZERO);
diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c
--- a/sys/fs/msdosfs/msdosfs_fat.c
+++ b/sys/fs/msdosfs/msdosfs_fat.c
@@ -80,8 +80,7 @@
u_long fatbn);
static __inline void
usemap_alloc(struct msdosfsmount *pmp, u_long cn);
-static __inline void
- usemap_free(struct msdosfsmount *pmp, u_long cn);
+static int usemap_free(struct msdosfsmount *pmp, u_long cn);
static int clusteralloc1(struct msdosfsmount *pmp, u_long start,
u_long count, u_long fillwith, u_long *retcluster,
u_long *got);
@@ -398,7 +397,7 @@
pmp->pm_flags |= MSDOSFS_FSIMOD;
}
-static __inline void
+static int
usemap_free(struct msdosfsmount *pmp, u_long cn)
{
@@ -408,35 +407,37 @@
pmp->pm_maxcluster));
KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
("usemap_free on ro msdosfs mount"));
+ if ((pmp->pm_inusemap[cn / N_INUSEBITS] &
+ (1U << (cn % N_INUSEBITS))) == 0) {
+ printf("%s: Freeing unused sector %ld %ld %x\n",
+ pmp->pm_mountp->mnt_stat.f_mntonname, cn, cn % N_INUSEBITS,
+ (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]);
+ msdosfs_integrity_error(pmp);
+ return (EINTEGRITY);
+ }
pmp->pm_freeclustercount++;
pmp->pm_flags |= MSDOSFS_FSIMOD;
- KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] &
- (1U << (cn % N_INUSEBITS))) != 0,
- ("Freeing unused sector %ld %ld %x", cn, cn % N_INUSEBITS,
- (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS));
+ return (0);
}
-int
-clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
+void
+clusterfree(struct msdosfsmount *pmp, u_long cluster)
{
int error;
u_long oldcn;
error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
- if (error)
- return (error);
+ if (error != 0)
+ return;
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
MSDOSFS_LOCK_MP(pmp);
- usemap_free(pmp, cluster);
+ error = usemap_free(pmp, cluster);
MSDOSFS_UNLOCK_MP(pmp);
- if (oldcnp)
- *oldcnp = oldcn;
- return (0);
}
/*
@@ -712,7 +713,7 @@
error = fatchain(pmp, start, count, fillwith);
if (error != 0) {
for (cl = start, n = count; n-- > 0;)
- usemap_free(pmp, cl++);
+ (void)usemap_free(pmp, cl++);
return (error);
}
#ifdef MSDOSFS_DEBUG
@@ -846,7 +847,12 @@
}
lbn = bn;
}
- usemap_free(pmp, cluster);
+ error = usemap_free(pmp, cluster);
+ if (error != 0) {
+ updatefats(pmp, bp, lbn);
+ MSDOSFS_UNLOCK_MP(pmp);
+ return (error);
+ }
switch (pmp->pm_fatmask) {
case FAT12_MASK:
readcn = getushort(bp->b_data + bo);
@@ -940,8 +946,13 @@
#endif
brelse(bp);
return (EINVAL);
- } else if (readcn == CLUST_FREE)
- usemap_free(pmp, cn);
+ } else if (readcn == CLUST_FREE) {
+ error = usemap_free(pmp, cn);
+ if (error != 0) {
+ brelse(bp);
+ return (error);
+ }
+ }
}
if (bp != NULL)
brelse(bp);
@@ -1043,7 +1054,7 @@
dep->de_fc[FC_LASTFC].fc_fsrcn,
0, cn);
if (error) {
- clusterfree(pmp, cn, NULL);
+ clusterfree(pmp, cn);
return (error);
}
frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -63,6 +63,29 @@
#include <fs/msdosfs/fat.h>
#include <fs/msdosfs/msdosfsmount.h>
+static int
+msdosfs_lookup_checker(struct msdosfsmount *pmp, struct vnode *dvp,
+ struct denode *tdp, struct vnode **vpp)
+{
+ struct vnode *vp;
+
+ vp = DETOV(tdp);
+
+ /*
+ * Lookup assumes that directory cannot be hardlinked.
+ * Corrupted msdosfs filesystem could break this assumption.
+ */
+ if (vp == dvp) {
+ vput(vp);
+ msdosfs_integrity_error(pmp);
+ *vpp = NULL;
+ return (EBADF);
+ }
+
+ *vpp = vp;
+ return (0);
+}
+
int
msdosfs_lookup(struct vop_cachedlookup_args *ap)
{
@@ -501,8 +524,7 @@
error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp);
if (error)
return (error);
- *vpp = DETOV(tdp);
- return (0);
+ return (msdosfs_lookup_checker(pmp, vdp, tdp, vpp));
}
/*
@@ -529,7 +551,9 @@
if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
&tdp)) != 0)
return (error);
- *vpp = DETOV(tdp);
+ if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp))
+ != 0)
+ return (error);
cnp->cn_flags |= SAVENAME;
return (0);
}
@@ -572,14 +596,23 @@
vput(*vpp);
goto restart;
}
+ error = msdosfs_lookup_checker(pmp, vdp, VTODE(*vpp), vpp);
+ if (error != 0)
+ return (error);
} else if (dp->de_StartCluster == scn && isadir) {
+ if (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.') {
+ /* fs is corrupted, non-dot lookup returned dvp */
+ msdosfs_integrity_error(pmp);
+ return (EBADF);
+ }
VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
} else {
if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
&tdp)) != 0)
return (error);
- *vpp = DETOV(tdp);
+ if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) != 0)
+ return (error);
}
/*
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -53,6 +53,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
+#include <sys/bufobj.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/iconv.h>
@@ -64,7 +65,9 @@
#include <sys/namei.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/rwlock.h>
#include <sys/stat.h>
+#include <sys/taskqueue.h>
#include <sys/vnode.h>
#include <geom/geom.h>
@@ -112,6 +115,7 @@
static int update_mp(struct mount *mp, struct thread *td);
static int mountmsdosfs(struct vnode *devvp, struct mount *mp);
+static void msdosfs_remount_ro(void *arg, int pending);
static vfs_fhtovp_t msdosfs_fhtovp;
static vfs_mount_t msdosfs_mount;
static vfs_root_t msdosfs_root;
@@ -227,7 +231,7 @@
static int
msdosfs_mount(struct mount *mp)
{
- struct vnode *devvp; /* vnode for blk device to mount */
+ struct vnode *devvp, *odevvp; /* vnode for blk device to mount */
struct thread *td;
/* msdosfs specific mount control block */
struct msdosfsmount *pmp = NULL;
@@ -300,17 +304,17 @@
* If upgrade to read-write by non-root, then verify
* that user has necessary permissions on the device.
*/
- devvp = pmp->pm_devvp;
- vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
- error = VOP_ACCESS(devvp, VREAD | VWRITE,
+ odevvp = pmp->pm_odevvp;
+ vn_lock(odevvp, LK_EXCLUSIVE | LK_RETRY);
+ error = VOP_ACCESS(odevvp, VREAD | VWRITE,
td->td_ucred, td);
if (error)
error = priv_check(td, PRIV_VFS_MOUNT_PERM);
if (error) {
- VOP_UNLOCK(devvp);
+ VOP_UNLOCK(odevvp);
return (error);
}
- VOP_UNLOCK(devvp);
+ VOP_UNLOCK(odevvp);
g_topology_lock();
error = g_access(pmp->pm_cp, 0, 1, 0);
g_topology_unlock();
@@ -337,6 +341,13 @@
mp->mnt_flag &= ~MNT_RDONLY;
MNT_IUNLOCK(mp);
}
+
+ /*
+ * Avoid namei() below. The "from" option is not set.
+ * Update of the devvp is pointless for this case.
+ */
+ if ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0)
+ return (0);
}
/*
* Not an update, or updating the name: look up the name
@@ -376,7 +387,7 @@
#endif
} else {
vput(devvp);
- if (devvp != pmp->pm_devvp)
+ if (devvp != pmp->pm_odevvp)
return (EINVAL); /* XXX needs translation */
}
if (error) {
@@ -399,11 +410,12 @@
}
static int
-mountmsdosfs(struct vnode *devvp, struct mount *mp)
+mountmsdosfs(struct vnode *odevvp, struct mount *mp)
{
struct msdosfsmount *pmp;
struct buf *bp;
struct cdev *dev;
+ struct vnode *devvp;
union bootsector *bsp;
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
@@ -418,10 +430,13 @@
pmp = NULL;
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+ devvp = mntfs_allocvp(mp, odevvp);
+ VOP_UNLOCK(odevvp);
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
dev = devvp->v_rdev;
if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0,
(uintptr_t)mp) == 0) {
- VOP_UNLOCK(devvp);
+ mntfs_freevp(devvp);
return (EBUSY);
}
g_topology_lock();
@@ -429,11 +444,14 @@
g_topology_unlock();
if (error != 0) {
atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0);
- VOP_UNLOCK(devvp);
+ mntfs_freevp(devvp);
return (error);
}
dev_ref(dev);
bo = &devvp->v_bufobj;
+ BO_LOCK(&odevvp->v_bufobj);
+ odevvp->v_bufobj.bo_flag |= BO_NOBUFS;
+ BO_UNLOCK(&odevvp->v_bufobj);
VOP_UNLOCK(devvp);
if (dev->si_iosize_max != 0)
mp->mnt_iosize_max = dev->si_iosize_max;
@@ -471,6 +489,8 @@
lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);
lockinit(&pmp->pm_checkpath_lock, 0, "msdoscp", 0, 0);
+ TASK_INIT(&pmp->pm_rw2ro_task, 0, msdosfs_remount_ro, pmp);
+
/*
* Initialize ownerships and permissions, since nothing else will
* initialize them iff we are mounting root.
@@ -558,6 +578,14 @@
}
pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
+ if ((off_t)pmp->pm_HugeSectors * pmp->pm_BytesPerSec <
+ pmp->pm_HugeSectors /* overflow */ ||
+ (off_t)pmp->pm_HugeSectors * pmp->pm_BytesPerSec >
+ cp->provider->mediasize /* past end of vol */) {
+ error = EINVAL;
+ goto error_exit;
+ }
+
pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */
pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
SecPerClust *= pmp->pm_BlkPerSec;
@@ -577,6 +605,10 @@
pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
}
+ if (pmp->pm_HugeSectors <= pmp->pm_firstcluster) {
+ error = EINVAL;
+ goto error_exit;
+ }
pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
SecPerClust + 1;
pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */
@@ -686,6 +718,7 @@
* fillinusemap() needs pm_devvp.
*/
pmp->pm_devvp = devvp;
+ pmp->pm_odevvp = odevvp;
pmp->pm_dev = dev;
/*
@@ -741,7 +774,12 @@
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
}
+ BO_LOCK(&odevvp->v_bufobj);
+ odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS;
+ BO_UNLOCK(&odevvp->v_bufobj);
atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0);
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
+ mntfs_freevp(devvp);
dev_rel(dev);
return (error);
}
@@ -818,11 +856,16 @@
if (susp)
vfs_write_resume(mp, VR_START_WRITE);
+ vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
g_topology_lock();
g_vfs_close(pmp->pm_cp);
g_topology_unlock();
+ BO_LOCK(&pmp->pm_odevvp->v_bufobj);
+ pmp->pm_odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS;
+ BO_UNLOCK(&pmp->pm_odevvp->v_bufobj);
atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0);
- vrele(pmp->pm_devvp);
+ mntfs_freevp(pmp->pm_devvp);
+ vrele(pmp->pm_odevvp);
dev_rel(pmp->pm_dev);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
lockdestroy(&pmp->pm_fatlock);
@@ -835,6 +878,47 @@
return (error);
}
+static void
+msdosfs_remount_ro(void *arg, int pending)
+{
+ struct msdosfsmount *pmp;
+ int error;
+
+ pmp = arg;
+
+ MSDOSFS_LOCK_MP(pmp);
+ if ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) {
+ while ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0)
+ msleep(&pmp->pm_flags, &pmp->pm_fatlock, PVFS,
+ "msdoserrro", hz);
+ } else if ((pmp->pm_mountp->mnt_flag & MNT_RDONLY) == 0) {
+ pmp->pm_flags |= MSDOSFS_ERR_RO;
+ MSDOSFS_UNLOCK_MP(pmp);
+ printf("remounting %s read-only due to corruption\n",
+ pmp->pm_mountp->mnt_stat.f_mntfromname);
+ error = vfs_remount_ro(pmp->pm_mountp);
+ if (error != 0)
+ printf("remounting %s read-only failed: error %d\n",
+ pmp->pm_mountp->mnt_stat.f_mntfromname, error);
+ else
+ printf("remounted %s read-only\n",
+ pmp->pm_mountp->mnt_stat.f_mntfromname);
+ MSDOSFS_LOCK_MP(pmp);
+ pmp->pm_flags &= ~MSDOSFS_ERR_RO;
+ wakeup(&pmp->pm_flags);
+ }
+ MSDOSFS_UNLOCK_MP(pmp);
+
+ vfs_unbusy(pmp->pm_mountp);
+}
+
+void
+msdosfs_integrity_error(struct msdosfsmount *pmp)
+{
+ if (vfs_busy(pmp->pm_mountp, MBF_NOWAIT) == 0)
+ taskqueue_enqueue(taskqueue_thread, &pmp->pm_rw2ro_task);
+}
+
static int
msdosfs_root(struct mount *mp, int flags, struct vnode **vpp)
{
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -1433,7 +1433,7 @@
return (0);
bad:
- clusterfree(pmp, newcluster, NULL);
+ clusterfree(pmp, newcluster);
bad2:
return (error);
}
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -59,6 +59,7 @@
#ifndef MAKEFS
#include <sys/lock.h>
#include <sys/lockmgr.h>
+#include <sys/_task.h>
#endif
#include <sys/tree.h>
@@ -82,6 +83,7 @@
mode_t pm_dirmask; /* mask to and with file protection bits
for directories */
struct vnode *pm_devvp; /* vnode for character device mounted */
+ struct vnode *pm_odevvp;/* real devfs vnode */
struct cdev *pm_dev; /* character device mounted */
struct bpb50 pm_bpb; /* BIOS parameter blk for this fs */
u_long pm_BlkPerSec; /* How many DEV_BSIZE blocks fit inside a physical sector */
@@ -115,6 +117,7 @@
#ifndef MAKEFS
struct lock pm_fatlock; /* lockmgr protecting allocations */
struct lock pm_checkpath_lock; /* protects doscheckpath result */
+ struct task pm_rw2ro_task; /* context for emergency remount ro */
#endif
};
@@ -263,5 +266,10 @@
#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */
#define MSDOSFS_FSIMOD 0x01000000
+#define MSDOSFS_ERR_RO 0x00800000 /* remouning ro due to error */
+
+#ifdef _KERNEL
+void msdosfs_integrity_error(struct msdosfsmount *pmp);
+#endif
#endif /* !_MSDOSFS_MSDOSFSMOUNT_H_ */
diff --git a/sys/geom/label/g_label_msdosfs.c b/sys/geom/label/g_label_msdosfs.c
--- a/sys/geom/label/g_label_msdosfs.c
+++ b/sys/geom/label/g_label_msdosfs.c
@@ -156,6 +156,12 @@
G_LABEL_DEBUG(2,
"MSDOSFS: FAT_FirstDataSector=0x%x, FAT_BytesPerSector=%d",
fat_FirstDataSector, fat_BytesPerSector);
+ if (fat_BytesPerSector == 0 ||
+ fat_BytesPerSector % pp->sectorsize != 0) {
+ G_LABEL_DEBUG(1, "MSDOSFS: %s: corrupted BPB",
+ pp->name);
+ goto error;
+ }
for (offset = fat_BytesPerSector * fat_FirstDataSector;;
offset += fat_BytesPerSector) {
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -2868,6 +2868,95 @@
free(buf, M_MOUNT);
}
+/*
+ * Force remount specified mount point to read-only. The argument
+ * must be busied to avoid parallel unmount attempts.
+ *
+ * Intended use is to prevent further writes if some metadata
+ * inconsistency is detected. Note that the function still flushes
+ * all cached metadata and data for the mount point, which might be
+ * not always suitable.
+ */
+int
+vfs_remount_ro(struct mount *mp)
+{
+ struct vfsoptlist *opts;
+ struct vfsopt *opt;
+ struct vnode *vp_covered, *rootvp;
+ int error;
+
+ KASSERT(mp->mnt_lockref > 0,
+ ("vfs_remount_ro: mp %p is not busied", mp));
+ KASSERT((mp->mnt_kern_flag & MNTK_UNMOUNT) == 0,
+ ("vfs_remount_ro: mp %p is being unmounted (and busy?)", mp));
+
+ rootvp = NULL;
+ vp_covered = mp->mnt_vnodecovered;
+ error = vget(vp_covered, LK_EXCLUSIVE | LK_NOWAIT);
+ if (error != 0)
+ return (error);
+ VI_LOCK(vp_covered);
+ if ((vp_covered->v_iflag & VI_MOUNT) != 0) {
+ VI_UNLOCK(vp_covered);
+ vput(vp_covered);
+ return (EBUSY);
+ }
+ vp_covered->v_iflag |= VI_MOUNT;
+ VI_UNLOCK(vp_covered);
+ vfs_op_enter(mp);
+ vn_seqc_write_begin(vp_covered);
+
+ MNT_ILOCK(mp);
+ if ((mp->mnt_flag & MNT_RDONLY) != 0) {
+ MNT_IUNLOCK(mp);
+ error = EBUSY;
+ goto out;
+ }
+ mp->mnt_flag |= MNT_UPDATE | MNT_FORCE | MNT_RDONLY;
+ rootvp = vfs_cache_root_clear(mp);
+ MNT_IUNLOCK(mp);
+
+ opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK | M_ZERO);
+ TAILQ_INIT(opts);
+ opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK | M_ZERO);
+ opt->name = strdup("ro", M_MOUNT);
+ opt->value = NULL;
+ TAILQ_INSERT_TAIL(opts, opt, link);
+ vfs_mergeopts(opts, mp->mnt_opt);
+ mp->mnt_optnew = opts;
+
+ error = VFS_MOUNT(mp);
+
+ if (error == 0) {
+ MNT_ILOCK(mp);
+ mp->mnt_flag &= ~(MNT_UPDATE | MNT_FORCE);
+ MNT_IUNLOCK(mp);
+ vfs_deallocate_syncvnode(mp);
+ if (mp->mnt_opt != NULL)
+ vfs_freeopts(mp->mnt_opt);
+ mp->mnt_opt = mp->mnt_optnew;
+ } else {
+ MNT_ILOCK(mp);
+ mp->mnt_flag &= ~(MNT_UPDATE | MNT_FORCE | MNT_RDONLY);
+ MNT_IUNLOCK(mp);
+ vfs_freeopts(mp->mnt_optnew);
+ }
+ mp->mnt_optnew = NULL;
+
+out:
+ vfs_op_exit(mp);
+ VI_LOCK(vp_covered);
+ vp_covered->v_iflag &= ~VI_MOUNT;
+ VI_UNLOCK(vp_covered);
+ vput(vp_covered);
+ vn_seqc_write_end(vp_covered);
+ if (rootvp != NULL) {
+ vn_seqc_write_end(rootvp);
+ vrele(rootvp);
+ }
+ return (error);
+}
+
/*
* Suspend write operations on all local writeable filesystems. Does
* full sync of them in the process.
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -1036,6 +1036,8 @@
void vfs_unregister_for_notification(struct mount *,
struct mount_upper_node *);
void vfs_unregister_upper(struct mount *, struct mount_upper_node *);
+int vfs_remount_ro(struct mount *mp);
+
extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */
extern struct mtx_padalign mountlist_mtx;
extern struct nfs_public nfs_pub;
diff --git a/usr.sbin/makefs/msdos/msdosfs_fat.c b/usr.sbin/makefs/msdos/msdosfs_fat.c
--- a/usr.sbin/makefs/msdos/msdosfs_fat.c
+++ b/usr.sbin/makefs/msdos/msdosfs_fat.c
@@ -408,24 +408,21 @@
pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS));
}
-int
-clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
+void
+clusterfree(struct msdosfsmount *pmp, u_long cluster)
{
int error;
u_long oldcn;
error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
- if (error)
- return (error);
+ if (error != 0)
+ return;
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
usemap_free(pmp, cluster);
- if (oldcnp)
- *oldcnp = oldcn;
- return (0);
}
/*
@@ -1024,7 +1021,7 @@
dep->de_fc[FC_LASTFC].fc_fsrcn,
0, cn);
if (error) {
- clusterfree(pmp, cn, NULL);
+ clusterfree(pmp, cn);
return (error);
}
frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
diff --git a/usr.sbin/makefs/msdos/msdosfs_vnops.c b/usr.sbin/makefs/msdos/msdosfs_vnops.c
--- a/usr.sbin/makefs/msdos/msdosfs_vnops.c
+++ b/usr.sbin/makefs/msdos/msdosfs_vnops.c
@@ -636,7 +636,7 @@
return dep;
bad:
- clusterfree(pmp, newcluster, NULL);
+ clusterfree(pmp, newcluster);
bad2:
errno = error;
return NULL;

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 25, 9:37 PM (2 h, 26 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26181840
Default Alt Text
D33721.id101088.diff (20 KB)

Event Timeline