Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137680784
D33721.id101088.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D33721.id101088.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D33721: Improve msdosfs robustness
Attached
Detach File
Event Timeline
Log In to Comment