mzap_upgrade() must use kmem_alloc()
[zfs.git] / module / zfs / zvol.c
index 125d58d..60ff64e 100644 (file)
@@ -49,6 +49,7 @@
 unsigned int zvol_inhibit_dev = 0;
 unsigned int zvol_major = ZVOL_MAJOR;
 unsigned int zvol_threads = 32;
+unsigned long zvol_max_discard_blocks = 16384;
 
 static taskq_t *zvol_taskq;
 static kmutex_t zvol_state_lock;
@@ -539,6 +540,14 @@ zvol_write(void *arg)
        dmu_tx_t *tx;
        rl_t *rl;
 
+       /*
+        * Annotate this call path with a flag that indicates that it is
+        * unsafe to use KM_SLEEP during memory allocations due to the
+        * potential for a deadlock.  KM_PUSHPAGE should be used instead.
+        */
+       ASSERT(!(current->flags & PF_NOFS));
+       current->flags |= PF_NOFS;
+
        if (req->cmd_flags & VDEV_REQ_FLUSH)
                zil_commit(zv->zv_zilog, ZVOL_OBJ);
 
@@ -547,7 +556,7 @@ zvol_write(void *arg)
         */
        if (size == 0) {
                blk_end_request(req, 0, size);
-               return;
+               goto out;
        }
 
        rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_WRITER);
@@ -561,7 +570,7 @@ zvol_write(void *arg)
                dmu_tx_abort(tx);
                zfs_range_unlock(rl);
                blk_end_request(req, -error, size);
-               return;
+               goto out;
        }
 
        error = dmu_write_req(zv->zv_objset, ZVOL_OBJ, req, tx);
@@ -577,6 +586,8 @@ zvol_write(void *arg)
                zil_commit(zv->zv_zilog, ZVOL_OBJ);
 
        blk_end_request(req, -error, size);
+out:
+       current->flags &= ~PF_NOFS;
 }
 
 #ifdef HAVE_BLK_QUEUE_DISCARD
@@ -591,14 +602,22 @@ zvol_discard(void *arg)
        int error;
        rl_t *rl;
 
+       /*
+        * Annotate this call path with a flag that indicates that it is
+        * unsafe to use KM_SLEEP during memory allocations due to the
+        * potential for a deadlock.  KM_PUSHPAGE should be used instead.
+        */
+       ASSERT(!(current->flags & PF_NOFS));
+       current->flags |= PF_NOFS;
+
        if (offset + size > zv->zv_volsize) {
                blk_end_request(req, -EIO, size);
-               return;
+               goto out;
        }
 
        if (size == 0) {
                blk_end_request(req, 0, size);
-               return;
+               goto out;
        }
 
        rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_WRITER);
@@ -612,6 +631,8 @@ zvol_discard(void *arg)
        zfs_range_unlock(rl);
 
        blk_end_request(req, -error, size);
+out:
+       current->flags &= ~PF_NOFS;
 }
 #endif /* HAVE_BLK_QUEUE_DISCARD */
 
@@ -1242,7 +1263,9 @@ __zvol_create_minor(const char *name)
        blk_queue_physical_block_size(zv->zv_queue, zv->zv_volblocksize);
        blk_queue_io_opt(zv->zv_queue, zv->zv_volblocksize);
 #ifdef HAVE_BLK_QUEUE_DISCARD
-       blk_queue_max_discard_sectors(zv->zv_queue, UINT_MAX);
+       blk_queue_max_discard_sectors(zv->zv_queue,
+           (zvol_max_discard_blocks * zv->zv_volblocksize) >> 9);
+       blk_queue_discard_granularity(zv->zv_queue, zv->zv_volblocksize);
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zv->zv_queue);
 #endif
 #ifdef HAVE_BLK_QUEUE_NONROT
@@ -1446,3 +1469,6 @@ MODULE_PARM_DESC(zvol_major, "Major number for zvol device");
 
 module_param(zvol_threads, uint, 0444);
 MODULE_PARM_DESC(zvol_threads, "Number of threads for zvol device");
+
+module_param(zvol_max_discard_blocks, ulong, 0444);
+MODULE_PARM_DESC(zvol_max_discard_blocks, "Max number of blocks to discard at once");