Commit 8967605e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'block-5.18-2022-05-06' of git://git.kernel.dk/linux-block

Pull block fixes from Jens Axboe:
 "A single revert for a change that isn't needed in 5.18, and a small
  series for s390/dasd"

* tag 'block-5.18-2022-05-06' of git://git.kernel.dk/linux-block:
  s390/dasd: Use kzalloc instead of kmalloc/memset
  s390/dasd: Fix read inconsistency for ESE DASD devices
  s390/dasd: Fix read for ESE with blksize < 4k
  s390/dasd: prevent double format of tracks for ESE devices
  s390/dasd: fix data corruption for ESE devices
  Revert "block: release rq qos structures for queue without disk"
parents b366bd7d f1c8781a
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@
#include "blk-pm.h"
#include "blk-cgroup.h"
#include "blk-throttle.h"
#include "blk-rq-qos.h"

struct dentry *blk_debugfs_root;

@@ -315,9 +314,6 @@ void blk_cleanup_queue(struct request_queue *q)
	 */
	blk_freeze_queue(q);

	/* cleanup rq qos structures for queue without disk */
	rq_qos_exit(q);

	blk_queue_flag_set(QUEUE_FLAG_DEAD, q);

	blk_sync_queue(q);
+15 −3
Original line number Diff line number Diff line
@@ -1422,6 +1422,13 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
		if (!cqr->lpm)
			cqr->lpm = dasd_path_get_opm(device);
	}
	/*
	 * remember the amount of formatted tracks to prevent double format on
	 * ESE devices
	 */
	if (cqr->block)
		cqr->trkcount = atomic_read(&cqr->block->trkcount);

	if (cqr->cpmode == 1) {
		rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
					 (long) cqr, cqr->lpm);
@@ -1639,6 +1646,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
	unsigned long now;
	int nrf_suppressed = 0;
	int fp_suppressed = 0;
	struct request *req;
	u8 *sense = NULL;
	int expires;

@@ -1739,7 +1747,12 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
	}

	if (dasd_ese_needs_format(cqr->block, irb)) {
		if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
		req = dasd_get_callback_data(cqr);
		if (!req) {
			cqr->status = DASD_CQR_ERROR;
			return;
		}
		if (rq_data_dir(req) == READ) {
			device->discipline->ese_read(cqr, irb);
			cqr->status = DASD_CQR_SUCCESS;
			cqr->stopclk = now;
@@ -2765,8 +2778,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
		 * complete a request partially.
		 */
		if (proc_bytes) {
			blk_update_request(req, BLK_STS_OK,
					   blk_rq_bytes(req) - proc_bytes);
			blk_update_request(req, BLK_STS_OK, proc_bytes);
			blk_mq_requeue_request(req, true);
		} else if (likely(!blk_should_fake_timeout(req->q))) {
			blk_mq_complete_request(req);
+22 −11
Original line number Diff line number Diff line
@@ -1480,7 +1480,7 @@ static int dasd_eckd_pe_handler(struct dasd_device *device,
{
	struct pe_handler_work_data *data;

	data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA);
	data = kzalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA);
	if (!data) {
		if (mutex_trylock(&dasd_pe_handler_mutex)) {
			data = pe_handler_worker;
@@ -1488,9 +1488,6 @@ static int dasd_eckd_pe_handler(struct dasd_device *device,
		} else {
			return -ENOMEM;
		}
	} else {
		memset(data, 0, sizeof(*data));
		data->isglobal = 0;
	}
	INIT_WORK(&data->worker, do_pe_handler_work);
	dasd_get_device(device);
@@ -3083,13 +3080,24 @@ static int dasd_eckd_format_device(struct dasd_device *base,
}

static bool test_and_set_format_track(struct dasd_format_entry *to_format,
				      struct dasd_block *block)
				      struct dasd_ccw_req *cqr)
{
	struct dasd_block *block = cqr->block;
	struct dasd_format_entry *format;
	unsigned long flags;
	bool rc = false;

	spin_lock_irqsave(&block->format_lock, flags);
	if (cqr->trkcount != atomic_read(&block->trkcount)) {
		/*
		 * The number of formatted tracks has changed after request
		 * start and we can not tell if the current track was involved.
		 * To avoid data corruption treat it as if the current track is
		 * involved
		 */
		rc = true;
		goto out;
	}
	list_for_each_entry(format, &block->format_list, list) {
		if (format->track == to_format->track) {
			rc = true;
@@ -3109,6 +3117,7 @@ static void clear_format_track(struct dasd_format_entry *format,
	unsigned long flags;

	spin_lock_irqsave(&block->format_lock, flags);
	atomic_inc(&block->trkcount);
	list_del_init(&format->list);
	spin_unlock_irqrestore(&block->format_lock, flags);
}
@@ -3145,7 +3154,7 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr,
	sector_t curr_trk;
	int rc;

	req = cqr->callback_data;
	req = dasd_get_callback_data(cqr);
	block = cqr->block;
	base = block->base;
	private = base->private;
@@ -3170,8 +3179,11 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr,
	}
	format->track = curr_trk;
	/* test if track is already in formatting by another thread */
	if (test_and_set_format_track(format, block))
	if (test_and_set_format_track(format, cqr)) {
		/* this is no real error so do not count down retries */
		cqr->retries++;
		return ERR_PTR(-EEXIST);
	}

	fdata.start_unit = curr_trk;
	fdata.stop_unit = curr_trk;
@@ -3270,12 +3282,11 @@ static int dasd_eckd_ese_read(struct dasd_ccw_req *cqr, struct irb *irb)
				cqr->proc_bytes = blk_count * blksize;
				return 0;
			}
			if (dst && !skip_block) {
				dst += off;
			if (dst && !skip_block)
				memset(dst, 0, blksize);
			} else {
			else
				skip_block--;
			}
			dst += blksize;
			blk_count++;
		}
	}
+14 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ struct dasd_ccw_req {
	void (*callback)(struct dasd_ccw_req *, void *data);
	void *callback_data;
	unsigned int proc_bytes;	/* bytes for partial completion */
	unsigned int trkcount;		/* count formatted tracks */
};

/*
@@ -610,6 +611,7 @@ struct dasd_block {

	struct list_head format_list;
	spinlock_t format_lock;
	atomic_t trkcount;
};

struct dasd_attention_data {
@@ -756,6 +758,18 @@ dasd_check_blocksize(int bsize)
	return 0;
}

/*
 * return the callback data of the original request in case there are
 * ERP requests build on top of it
 */
static inline void *dasd_get_callback_data(struct dasd_ccw_req *cqr)
{
	while (cqr->refers)
		cqr = cqr->refers;

	return cqr->callback_data;
}

/* externals in dasd.c */
#define DASD_PROFILE_OFF	 0
#define DASD_PROFILE_ON 	 1