kernel - Refuse to swapoff under certain conditions
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 6 Oct 2017 05:59:40 +0000 (22:59 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 6 Oct 2017 06:25:06 +0000 (23:25 -0700)
* Both tmpfs and vn can't handle swapoff's method of bringing pages
  back in from the swap partition being decomissioned.

* Fixing this properly is fairly involved. The normal swapoff procedure
  is to page swap into the related VM object, but tmpfs and vn use their
  VM objects ONLY to track swap blocks and not for vm_page manipulation,
  so that just won't work.  In addition, the swap code may associate
  a swap block with a VM object before issuing the write I/O to page
  out the data, and the swapoff code's asynchronous pagein might cause
  problems.

  For now, just make sure that swapoff refuses to remove the partition
  under these conditions, so it doesn't blow up tmpfs or vn.

sys/dev/disk/vn/vn.c
sys/vfs/tmpfs/tmpfs_subr.c
sys/vm/swap_pager.c
sys/vm/vm_object.h

index f88d952..9ede59b 100644 (file)
@@ -635,6 +635,7 @@ vniocattach_swap(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev,
        vn->sc_object = swap_pager_alloc(NULL,
                                         vn->sc_secsize * (off_t)vio->vn_size,
                                         VM_PROT_DEFAULT, 0);
+       vm_object_set_flag(vn->sc_object, OBJ_NOPAGEIN);
        IFOPT(vn, VN_RESERVE) {
                if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) {
                        vm_pager_deallocate(vn->sc_object);
index 546d939..0c46d82 100644 (file)
@@ -163,6 +163,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
                    swap_pager_alloc(NULL, 0, VM_PROT_DEFAULT, 0);
                nnode->tn_reg.tn_aobj_pages = 0;
                nnode->tn_size = 0;
+               vm_object_set_flag(nnode->tn_reg.tn_aobj, OBJ_NOPAGEIN);
                break;
 
        default:
index afd73b2..f5d401b 100644 (file)
@@ -2154,6 +2154,17 @@ swap_pager_swapoff(int devidx)
                                vm_object_drop(object);
                                goto skip;
                        }
+
+                       /*
+                        * Object is special in that we can't just pagein
+                        * into vm_page's in it (tmpfs, vn).
+                        */
+                       if ((object->flags & OBJ_NOPAGEIN) &&
+                           RB_ROOT(&object->swblock_root)) {
+                               vm_object_drop(object);
+                               goto skip;
+                       }
+
                        info.object = object;
                        info.shared = 0;
                        info.devidx = devidx;
index b650211..a609a17 100644 (file)
@@ -202,17 +202,22 @@ struct vm_object {
 /*
  * Flags
  *
- * NOTE: OBJ_ONEMAPPING only applies to DEFAULT and SWAP objects.  It
- *      may be gratuitously re-cleared in other cases but will already be
- *      clear in those cases.  It might not be set on other object types
- *      (particularly OBJT_VNODE).
+ * OBJ_ONEMAPPING - Only applies to DEFAULT and SWAP objects.  It may be
+ *                 gratuitously re-cleared in other cases but will already
+ *                 be clear in those cases.  It might not be set on other
+ *                 object types (particularly OBJT_VNODE).
+ *
+ * OBJ_NOPAGEIN   - vn and tmpfs set this flag, indicating to swapoff
+ *                 that the objects aren't intended to have any vm_page's,
+ *                 only swap blocks.  vn and tmpfs don't know how to deal
+ *                 with any actual pages.
  */
 #define OBJ_UNUSED0001 0x0001          /* backing_object/shadow changing */
 #define OBJ_ONSHADOW   0x0002          /* backing_object on shadow list */
 #define OBJ_ACTIVE     0x0004          /* active objects */
 #define OBJ_DEAD       0x0008          /* dead objects (during rundown) */
 #define        OBJ_NOSPLIT     0x0010          /* dont split this object */
-#define OBJ_UNUSED0040 0x0040
+#define OBJ_NOPAGEIN   0x0040          /* special OBJT_SWAP */
 #define        OBJ_WRITEABLE   0x0080          /* object has been made writable */
 #define OBJ_MIGHTBEDIRTY 0x0100                /* object might be dirty */
 #define OBJ_CLEANING   0x0200