git: 171b75b0efd0 - stable/13 - msdosfs: add msdosfs_integrity_error()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 15 Jan 2022 00:51:44 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=171b75b0efd0bb56597acb3c12f57db03fabc660

commit 171b75b0efd0bb56597acb3c12f57db03fabc660
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-12-25 21:20:56 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-01-14 18:11:02 +0000

    msdosfs: add msdosfs_integrity_error()
    
    (cherry picked from commit b2e4b635844091de0601f5b7157d87115386b2a9)
---
 sys/fs/msdosfs/msdosfs_vfsops.c | 58 +++++++++++++++++++++++++++++++++++++++++
 sys/fs/msdosfs/msdosfsmount.h   |  7 +++++
 2 files changed, 65 insertions(+)

diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 77942ed88ce4..e09a75a698d7 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -65,6 +65,7 @@
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/stat.h>
+#include <sys/taskqueue.h>
 #include <sys/vnode.h>
 
 #include <geom/geom.h>
@@ -112,6 +113,7 @@ struct iconv_functions *msdosfs_iconv;
 
 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;
@@ -337,6 +339,13 @@ msdosfs_mount(struct mount *mp)
 			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
@@ -471,6 +480,8 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
 	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.
@@ -847,6 +858,53 @@ msdosfs_unmount(struct mount *mp, int mntflags)
 	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("%s: remounting read-only due to corruption\n",
+		    pmp->pm_mountp->mnt_stat.f_mntfromname);
+		error = vfs_remount_ro(pmp->pm_mountp);
+		if (error != 0)
+			printf("%s: remounting 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)
+{
+	int error;
+
+	error = vfs_busy(pmp->pm_mountp, MBF_NOWAIT);
+	if (error == 0)
+		taskqueue_enqueue(taskqueue_thread, &pmp->pm_rw2ro_task);
+	else
+		printf("%s: integrity error busying failed, error %d\n",
+		    pmp->pm_mountp->mnt_stat.f_mntfromname, error);
+}
+
 static int
 msdosfs_root(struct mount *mp, int flags, struct vnode **vpp)
 {
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index 46a02e611cf5..6a0ba896dff5 100644
--- 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>
 
@@ -115,6 +116,7 @@ struct msdosfsmount {
 #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 +265,10 @@ struct msdosfs_args {
 #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_ */