The branch main has been updated by kib:

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

commit b2e4b635844091de0601f5b7157d87115386b2a9
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-12-25 21:20:56 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-01-08 04:20:48 +0000

    msdosfs: add msdosfs_integrity_error()
    
    A function to remount the filesystem from rw to ro on integrity error.
    The work is performed in taskqueue to allow the call to be done from
    almost arbitrary context where erronous state was detected.
    
    Tested by:      pho
    Reviewed by:    markj, mckusick
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D33721
---
 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 8ef46e063420..3c2606ab5a91 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_ */

Reply via email to