block: move cmdfilter from gendisk to request_queue

cmd_filter works only for the block layer SG_IO with SCSI block
devices. It breaks scsi/sg.c, bsg, and the block layer SG_IO with SCSI
character devices (such as st). We hit a kernel crash with them.

The problem is that cmd_filter code accesses to gendisk (having struct
blk_scsi_cmd_filter) via inode->i_bdev->bd_disk. It works for only
SCSI block device files. With character device files, inode->i_bdev
leads you to struct cdev. inode->i_bdev->bd_disk->blk_scsi_cmd_filter
isn't safe.

SCSI ULDs don't expose gendisk; they keep it private. bsg needs to be
independent on any protocols. We shouldn't change ULDs to expose their
gendisk.

This patch moves struct blk_scsi_cmd_filter from gendisk to
request_queue, a common object, which eveyone can access to.

The user interface doesn't change; users can change the filters via
/sys/block/. gendisk has a pointer to request_queue so the cmd_filter
code accesses to struct blk_scsi_cmd_filter.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 3d36270..9d28b9f 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -641,6 +641,7 @@
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	int timeout;
 	unsigned long ul_timeout;
+	struct request_queue *q;
 
 	if (count < SZ_SG_IO_HDR)
 		return -EINVAL;
@@ -689,7 +690,9 @@
 		sg_remove_request(sfp, srp);
 		return -EFAULT;
 	}
-	if (read_only && !blk_verify_command(file, cmnd)) {
+	q = sfp->parentdp->device->request_queue;
+	if (read_only && blk_verify_command(&q->cmd_filter, cmnd,
+					    file->f_mode & FMODE_WRITE)) {
 		sg_remove_request(sfp, srp);
 		return -EPERM;
 	}
@@ -793,6 +796,7 @@
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
+
 	SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: %s, cmd=0x%x\n",
 				   sdp->disk->disk_name, (int) cmd_in));
 	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
@@ -1057,11 +1061,14 @@
 			return -ENODEV;
 		if (read_only) {
 			unsigned char opcode = WRITE_6;
+			struct request_queue *q = sdp->device->request_queue;
 			Scsi_Ioctl_Command __user *siocp = p;
 
 			if (copy_from_user(&opcode, siocp->data, 1))
 				return -EFAULT;
-			if (!blk_verify_command(filp, &opcode))
+			if (blk_verify_command(&q->cmd_filter,
+					       &opcode,
+					       filp->f_mode & FMODE_WRITE))
 				return -EPERM;
 		}
 		return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);