Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: (27 commits) block: remove unused copy_io_context() Documentation: remove anticipatory scheduler info block: remove REQ_HARDBARRIER ioprio: rcu_read_lock/unlock protect find_task_by_vpid call (V2) ioprio: fix RCU locking around task dereference block: ioctl: fix information leak to userland block: read i_size with i_size_read() cciss: fix proc warning on attempt to remove non-existant directory bio: take care not overflow page count when mapping/copying user data block: limit vec count in bio_kmalloc() and bio_alloc_map_data() block: take care not to overflow when calculating total iov length block: check for proper length of iov entries in blk_rq_map_user_iov() cciss: remove controllers supported by hpsa cciss: use usleep_range not msleep for small sleeps cciss: limit commands allocated on reset_devices cciss: Use kernel provided PCI state save and restore functions cciss: fix board status waiting code drbd: Removed checks for REQ_HARDBARRIER on incomming BIOs drbd: REQ_HARDBARRIER -> REQ_FUA transition for meta data accesses drbd: Removed the BIO_RW_BARRIER support form the receiver/epoch code ...
This commit is contained in:
commit
8a9f772c14
@ -16,7 +16,7 @@ you can do so by typing:
|
|||||||
As of the Linux 2.6.10 kernel, it is now possible to change the
|
As of the Linux 2.6.10 kernel, it is now possible to change the
|
||||||
IO scheduler for a given block device on the fly (thus making it possible,
|
IO scheduler for a given block device on the fly (thus making it possible,
|
||||||
for instance, to set the CFQ scheduler for the system default, but
|
for instance, to set the CFQ scheduler for the system default, but
|
||||||
set a specific device to use the anticipatory or noop schedulers - which
|
set a specific device to use the deadline or noop schedulers - which
|
||||||
can improve that device's throughput).
|
can improve that device's throughput).
|
||||||
|
|
||||||
To set a specific scheduler, simply do this:
|
To set a specific scheduler, simply do this:
|
||||||
@ -31,7 +31,7 @@ a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
|
|||||||
will be displayed, with the currently selected scheduler in brackets:
|
will be displayed, with the currently selected scheduler in brackets:
|
||||||
|
|
||||||
# cat /sys/block/hda/queue/scheduler
|
# cat /sys/block/hda/queue/scheduler
|
||||||
noop anticipatory deadline [cfq]
|
noop deadline [cfq]
|
||||||
# echo anticipatory > /sys/block/hda/queue/scheduler
|
# echo deadline > /sys/block/hda/queue/scheduler
|
||||||
# cat /sys/block/hda/queue/scheduler
|
# cat /sys/block/hda/queue/scheduler
|
||||||
noop [anticipatory] deadline cfq
|
noop [deadline] cfq
|
||||||
|
@ -706,7 +706,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||||||
arch/x86/kernel/cpu/cpufreq/elanfreq.c.
|
arch/x86/kernel/cpu/cpufreq/elanfreq.c.
|
||||||
|
|
||||||
elevator= [IOSCHED]
|
elevator= [IOSCHED]
|
||||||
Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
|
Format: {"cfq" | "deadline" | "noop"}
|
||||||
See Documentation/block/as-iosched.txt and
|
See Documentation/block/as-iosched.txt and
|
||||||
Documentation/block/deadline-iosched.txt for details.
|
Documentation/block/deadline-iosched.txt for details.
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ three rotations, respectively, to balance the tree), with slightly slower
|
|||||||
To quote Linux Weekly News:
|
To quote Linux Weekly News:
|
||||||
|
|
||||||
There are a number of red-black trees in use in the kernel.
|
There are a number of red-black trees in use in the kernel.
|
||||||
The anticipatory, deadline, and CFQ I/O schedulers all employ
|
The deadline and CFQ I/O schedulers employ rbtrees to
|
||||||
rbtrees to track requests; the packet CD/DVD driver does the same.
|
track requests; the packet CD/DVD driver does the same.
|
||||||
The high-resolution timer code uses an rbtree to organize outstanding
|
The high-resolution timer code uses an rbtree to organize outstanding
|
||||||
timer requests. The ext3 filesystem tracks directory entries in a
|
timer requests. The ext3 filesystem tracks directory entries in a
|
||||||
red-black tree. Virtual memory areas (VMAs) are tracked with red-black
|
red-black tree. Virtual memory areas (VMAs) are tracked with red-black
|
||||||
|
@ -1194,13 +1194,6 @@ static int __make_request(struct request_queue *q, struct bio *bio)
|
|||||||
int where = ELEVATOR_INSERT_SORT;
|
int where = ELEVATOR_INSERT_SORT;
|
||||||
int rw_flags;
|
int rw_flags;
|
||||||
|
|
||||||
/* REQ_HARDBARRIER is no more */
|
|
||||||
if (WARN_ONCE(bio->bi_rw & REQ_HARDBARRIER,
|
|
||||||
"block: HARDBARRIER is deprecated, use FLUSH/FUA instead\n")) {
|
|
||||||
bio_endio(bio, -EOPNOTSUPP);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* low level driver can indicate that it wants pages above a
|
* low level driver can indicate that it wants pages above a
|
||||||
* certain limit bounced to low memory (ie for highmem, or even
|
* certain limit bounced to low memory (ie for highmem, or even
|
||||||
@ -1351,7 +1344,7 @@ static void handle_bad_sector(struct bio *bio)
|
|||||||
bdevname(bio->bi_bdev, b),
|
bdevname(bio->bi_bdev, b),
|
||||||
bio->bi_rw,
|
bio->bi_rw,
|
||||||
(unsigned long long)bio->bi_sector + bio_sectors(bio),
|
(unsigned long long)bio->bi_sector + bio_sectors(bio),
|
||||||
(long long)(bio->bi_bdev->bd_inode->i_size >> 9));
|
(long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
|
||||||
|
|
||||||
set_bit(BIO_EOF, &bio->bi_flags);
|
set_bit(BIO_EOF, &bio->bi_flags);
|
||||||
}
|
}
|
||||||
@ -1404,7 +1397,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Test device or partition size, when known. */
|
/* Test device or partition size, when known. */
|
||||||
maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
|
maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
|
||||||
if (maxsector) {
|
if (maxsector) {
|
||||||
sector_t sector = bio->bi_sector;
|
sector_t sector = bio->bi_sector;
|
||||||
|
|
||||||
|
@ -153,20 +153,6 @@ struct io_context *get_io_context(gfp_t gfp_flags, int node)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_io_context);
|
EXPORT_SYMBOL(get_io_context);
|
||||||
|
|
||||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc)
|
|
||||||
{
|
|
||||||
struct io_context *src = *psrc;
|
|
||||||
struct io_context *dst = *pdst;
|
|
||||||
|
|
||||||
if (src) {
|
|
||||||
BUG_ON(atomic_long_read(&src->refcount) == 0);
|
|
||||||
atomic_long_inc(&src->refcount);
|
|
||||||
put_io_context(dst);
|
|
||||||
*pdst = src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(copy_io_context);
|
|
||||||
|
|
||||||
static int __init blk_ioc_init(void)
|
static int __init blk_ioc_init(void)
|
||||||
{
|
{
|
||||||
iocontext_cachep = kmem_cache_create("blkdev_ioc",
|
iocontext_cachep = kmem_cache_create("blkdev_ioc",
|
||||||
|
@ -205,6 +205,8 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
|
|||||||
unaligned = 1;
|
unaligned = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!iov[i].iov_len)
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unaligned || (q->dma_pad_mask & len) || map_data)
|
if (unaligned || (q->dma_pad_mask & len) || map_data)
|
||||||
|
@ -744,13 +744,13 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
|||||||
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
|
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
|
||||||
return 0;
|
return 0;
|
||||||
case BLKGETSIZE:
|
case BLKGETSIZE:
|
||||||
size = bdev->bd_inode->i_size;
|
size = i_size_read(bdev->bd_inode);
|
||||||
if ((size >> 9) > ~0UL)
|
if ((size >> 9) > ~0UL)
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
return compat_put_ulong(arg, size >> 9);
|
return compat_put_ulong(arg, size >> 9);
|
||||||
|
|
||||||
case BLKGETSIZE64_32:
|
case BLKGETSIZE64_32:
|
||||||
return compat_put_u64(arg, bdev->bd_inode->i_size);
|
return compat_put_u64(arg, i_size_read(bdev->bd_inode));
|
||||||
|
|
||||||
case BLKTRACESETUP32:
|
case BLKTRACESETUP32:
|
||||||
case BLKTRACESTART: /* compatible */
|
case BLKTRACESTART: /* compatible */
|
||||||
|
@ -429,7 +429,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
|
|||||||
q->nr_sorted--;
|
q->nr_sorted--;
|
||||||
|
|
||||||
boundary = q->end_sector;
|
boundary = q->end_sector;
|
||||||
stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED;
|
stop_flags = REQ_SOFTBARRIER | REQ_STARTED;
|
||||||
list_for_each_prev(entry, &q->queue_head) {
|
list_for_each_prev(entry, &q->queue_head) {
|
||||||
struct request *pos = list_entry_rq(entry);
|
struct request *pos = list_entry_rq(entry);
|
||||||
|
|
||||||
@ -691,7 +691,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
|
|||||||
void __elv_add_request(struct request_queue *q, struct request *rq, int where,
|
void __elv_add_request(struct request_queue *q, struct request *rq, int where,
|
||||||
int plug)
|
int plug)
|
||||||
{
|
{
|
||||||
if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
|
if (rq->cmd_flags & REQ_SOFTBARRIER) {
|
||||||
/* barriers are scheduling boundary, update end_sector */
|
/* barriers are scheduling boundary, update end_sector */
|
||||||
if (rq->cmd_type == REQ_TYPE_FS ||
|
if (rq->cmd_type == REQ_TYPE_FS ||
|
||||||
(rq->cmd_flags & REQ_DISCARD)) {
|
(rq->cmd_flags & REQ_DISCARD)) {
|
||||||
|
@ -125,7 +125,7 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
|
|||||||
start >>= 9;
|
start >>= 9;
|
||||||
len >>= 9;
|
len >>= 9;
|
||||||
|
|
||||||
if (start + len > (bdev->bd_inode->i_size >> 9))
|
if (start + len > (i_size_read(bdev->bd_inode) >> 9))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (secure)
|
if (secure)
|
||||||
flags |= BLKDEV_DISCARD_SECURE;
|
flags |= BLKDEV_DISCARD_SECURE;
|
||||||
@ -242,6 +242,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||||||
* We need to set the startsect first, the driver may
|
* We need to set the startsect first, the driver may
|
||||||
* want to override it.
|
* want to override it.
|
||||||
*/
|
*/
|
||||||
|
memset(&geo, 0, sizeof(geo));
|
||||||
geo.start = get_start_sect(bdev);
|
geo.start = get_start_sect(bdev);
|
||||||
ret = disk->fops->getgeo(bdev, &geo);
|
ret = disk->fops->getgeo(bdev, &geo);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -307,12 +308,12 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||||||
ret = blkdev_reread_part(bdev);
|
ret = blkdev_reread_part(bdev);
|
||||||
break;
|
break;
|
||||||
case BLKGETSIZE:
|
case BLKGETSIZE:
|
||||||
size = bdev->bd_inode->i_size;
|
size = i_size_read(bdev->bd_inode);
|
||||||
if ((size >> 9) > ~0UL)
|
if ((size >> 9) > ~0UL)
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
return put_ulong(arg, size >> 9);
|
return put_ulong(arg, size >> 9);
|
||||||
case BLKGETSIZE64:
|
case BLKGETSIZE64:
|
||||||
return put_u64(arg, bdev->bd_inode->i_size);
|
return put_u64(arg, i_size_read(bdev->bd_inode));
|
||||||
case BLKTRACESTART:
|
case BLKTRACESTART:
|
||||||
case BLKTRACESTOP:
|
case BLKTRACESTOP:
|
||||||
case BLKTRACESETUP:
|
case BLKTRACESETUP:
|
||||||
|
@ -321,33 +321,47 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
|
|||||||
if (hdr->iovec_count) {
|
if (hdr->iovec_count) {
|
||||||
const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
|
const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
|
||||||
size_t iov_data_len;
|
size_t iov_data_len;
|
||||||
struct sg_iovec *iov;
|
struct sg_iovec *sg_iov;
|
||||||
|
struct iovec *iov;
|
||||||
|
int i;
|
||||||
|
|
||||||
iov = kmalloc(size, GFP_KERNEL);
|
sg_iov = kmalloc(size, GFP_KERNEL);
|
||||||
if (!iov) {
|
if (!sg_iov) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy_from_user(iov, hdr->dxferp, size)) {
|
if (copy_from_user(sg_iov, hdr->dxferp, size)) {
|
||||||
kfree(iov);
|
kfree(sg_iov);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sum up the vecs, making sure they don't overflow
|
||||||
|
*/
|
||||||
|
iov = (struct iovec *) sg_iov;
|
||||||
|
iov_data_len = 0;
|
||||||
|
for (i = 0; i < hdr->iovec_count; i++) {
|
||||||
|
if (iov_data_len + iov[i].iov_len < iov_data_len) {
|
||||||
|
kfree(sg_iov);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
iov_data_len += iov[i].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
/* SG_IO howto says that the shorter of the two wins */
|
/* SG_IO howto says that the shorter of the two wins */
|
||||||
iov_data_len = iov_length((struct iovec *)iov,
|
|
||||||
hdr->iovec_count);
|
|
||||||
if (hdr->dxfer_len < iov_data_len) {
|
if (hdr->dxfer_len < iov_data_len) {
|
||||||
hdr->iovec_count = iov_shorten((struct iovec *)iov,
|
hdr->iovec_count = iov_shorten(iov,
|
||||||
hdr->iovec_count,
|
hdr->iovec_count,
|
||||||
hdr->dxfer_len);
|
hdr->dxfer_len);
|
||||||
iov_data_len = hdr->dxfer_len;
|
iov_data_len = hdr->dxfer_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
|
ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count,
|
||||||
iov_data_len, GFP_KERNEL);
|
iov_data_len, GFP_KERNEL);
|
||||||
kfree(iov);
|
kfree(sg_iov);
|
||||||
} else if (hdr->dxfer_len)
|
} else if (hdr->dxfer_len)
|
||||||
ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
|
ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
@ -180,9 +180,6 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
BUG();
|
BUG();
|
||||||
bio_endio(bio, -ENXIO);
|
bio_endio(bio, -ENXIO);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (bio->bi_rw & REQ_HARDBARRIER) {
|
|
||||||
bio_endio(bio, -EOPNOTSUPP);
|
|
||||||
return 0;
|
|
||||||
} else if (bio->bi_io_vec == NULL) {
|
} else if (bio->bi_io_vec == NULL) {
|
||||||
printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
|
printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
|
||||||
BUG();
|
BUG();
|
||||||
|
@ -113,6 +113,8 @@ static struct board_type products[] = {
|
|||||||
{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
|
{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
|
||||||
{0x40910E11, "Smart Array 6i", &SA5_access},
|
{0x40910E11, "Smart Array 6i", &SA5_access},
|
||||||
{0x3225103C, "Smart Array P600", &SA5_access},
|
{0x3225103C, "Smart Array P600", &SA5_access},
|
||||||
|
{0x3223103C, "Smart Array P800", &SA5_access},
|
||||||
|
{0x3234103C, "Smart Array P400", &SA5_access},
|
||||||
{0x3235103C, "Smart Array P400i", &SA5_access},
|
{0x3235103C, "Smart Array P400i", &SA5_access},
|
||||||
{0x3211103C, "Smart Array E200i", &SA5_access},
|
{0x3211103C, "Smart Array E200i", &SA5_access},
|
||||||
{0x3212103C, "Smart Array E200", &SA5_access},
|
{0x3212103C, "Smart Array E200", &SA5_access},
|
||||||
@ -3753,7 +3755,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
|
|||||||
for (i = 0; i < MAX_CONFIG_WAIT; i++) {
|
for (i = 0; i < MAX_CONFIG_WAIT; i++) {
|
||||||
if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
|
if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
|
||||||
break;
|
break;
|
||||||
msleep(10);
|
usleep_range(10000, 20000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3937,10 +3939,9 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
|
|||||||
*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
|
*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
|
||||||
subsystem_vendor_id;
|
subsystem_vendor_id;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(products); i++) {
|
for (i = 0; i < ARRAY_SIZE(products); i++)
|
||||||
if (*board_id == products[i].board_id)
|
if (*board_id == products[i].board_id)
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
|
dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
|
||||||
*board_id);
|
*board_id);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -3971,18 +3972,31 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
|
static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
|
||||||
|
void __iomem *vaddr, int wait_for_ready)
|
||||||
|
#define BOARD_READY 1
|
||||||
|
#define BOARD_NOT_READY 0
|
||||||
{
|
{
|
||||||
int i;
|
int i, iterations;
|
||||||
u32 scratchpad;
|
u32 scratchpad;
|
||||||
|
|
||||||
for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
|
if (wait_for_ready)
|
||||||
scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
|
iterations = CCISS_BOARD_READY_ITERATIONS;
|
||||||
if (scratchpad == CCISS_FIRMWARE_READY)
|
else
|
||||||
return 0;
|
iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
|
||||||
|
|
||||||
|
for (i = 0; i < iterations; i++) {
|
||||||
|
scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
|
||||||
|
if (wait_for_ready) {
|
||||||
|
if (scratchpad == CCISS_FIRMWARE_READY)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (scratchpad != CCISS_FIRMWARE_READY)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
|
msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
|
||||||
}
|
}
|
||||||
dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
|
dev_warn(&pdev->dev, "board not ready, timed out.\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4031,6 +4045,11 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
|
|||||||
static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
|
static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
|
||||||
{
|
{
|
||||||
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
|
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
|
||||||
|
|
||||||
|
/* Limit commands in memory limited kdump scenario. */
|
||||||
|
if (reset_devices && h->max_commands > 32)
|
||||||
|
h->max_commands = 32;
|
||||||
|
|
||||||
if (h->max_commands < 16) {
|
if (h->max_commands < 16) {
|
||||||
dev_warn(&h->pdev->dev, "Controller reports "
|
dev_warn(&h->pdev->dev, "Controller reports "
|
||||||
"max supported commands of %d, an obvious lie. "
|
"max supported commands of %d, an obvious lie. "
|
||||||
@ -4148,7 +4167,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
|
|||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_out_free_res;
|
goto err_out_free_res;
|
||||||
}
|
}
|
||||||
err = cciss_wait_for_board_ready(h);
|
err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out_free_res;
|
goto err_out_free_res;
|
||||||
err = cciss_find_cfgtables(h);
|
err = cciss_find_cfgtables(h);
|
||||||
@ -4313,36 +4332,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
|
|||||||
#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
|
#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
|
||||||
#define cciss_noop(p) cciss_message(p, 3, 0)
|
#define cciss_noop(p) cciss_message(p, 3, 0)
|
||||||
|
|
||||||
static __devinit int cciss_reset_msi(struct pci_dev *pdev)
|
|
||||||
{
|
|
||||||
/* the #defines are stolen from drivers/pci/msi.h. */
|
|
||||||
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
|
|
||||||
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
|
||||||
|
|
||||||
int pos;
|
|
||||||
u16 control = 0;
|
|
||||||
|
|
||||||
pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
|
|
||||||
if (pos) {
|
|
||||||
pci_read_config_word(pdev, msi_control_reg(pos), &control);
|
|
||||||
if (control & PCI_MSI_FLAGS_ENABLE) {
|
|
||||||
dev_info(&pdev->dev, "resetting MSI\n");
|
|
||||||
pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
|
|
||||||
if (pos) {
|
|
||||||
pci_read_config_word(pdev, msi_control_reg(pos), &control);
|
|
||||||
if (control & PCI_MSIX_FLAGS_ENABLE) {
|
|
||||||
dev_info(&pdev->dev, "resetting MSI-X\n");
|
|
||||||
pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cciss_controller_hard_reset(struct pci_dev *pdev,
|
static int cciss_controller_hard_reset(struct pci_dev *pdev,
|
||||||
void * __iomem vaddr, bool use_doorbell)
|
void * __iomem vaddr, bool use_doorbell)
|
||||||
{
|
{
|
||||||
@ -4397,17 +4386,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
|
|||||||
* states or using the doorbell register. */
|
* states or using the doorbell register. */
|
||||||
static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
|
static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 saved_config_space[32];
|
|
||||||
u64 cfg_offset;
|
u64 cfg_offset;
|
||||||
u32 cfg_base_addr;
|
u32 cfg_base_addr;
|
||||||
u64 cfg_base_addr_index;
|
u64 cfg_base_addr_index;
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
unsigned long paddr;
|
unsigned long paddr;
|
||||||
u32 misc_fw_support, active_transport;
|
u32 misc_fw_support, active_transport;
|
||||||
int rc, i;
|
int rc;
|
||||||
CfgTable_struct __iomem *cfgtable;
|
CfgTable_struct __iomem *cfgtable;
|
||||||
bool use_doorbell;
|
bool use_doorbell;
|
||||||
u32 board_id;
|
u32 board_id;
|
||||||
|
u16 command_register;
|
||||||
|
|
||||||
/* For controllers as old a the p600, this is very nearly
|
/* For controllers as old a the p600, this is very nearly
|
||||||
* the same thing as
|
* the same thing as
|
||||||
@ -4417,14 +4406,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
|
|||||||
* pci_set_power_state(pci_dev, PCI_D0);
|
* pci_set_power_state(pci_dev, PCI_D0);
|
||||||
* pci_restore_state(pci_dev);
|
* pci_restore_state(pci_dev);
|
||||||
*
|
*
|
||||||
* but we can't use these nice canned kernel routines on
|
|
||||||
* kexec, because they also check the MSI/MSI-X state in PCI
|
|
||||||
* configuration space and do the wrong thing when it is
|
|
||||||
* set/cleared. Also, the pci_save/restore_state functions
|
|
||||||
* violate the ordering requirements for restoring the
|
|
||||||
* configuration space from the CCISS document (see the
|
|
||||||
* comment below). So we roll our own ....
|
|
||||||
*
|
|
||||||
* For controllers newer than the P600, the pci power state
|
* For controllers newer than the P600, the pci power state
|
||||||
* method of resetting doesn't work so we have another way
|
* method of resetting doesn't work so we have another way
|
||||||
* using the doorbell register.
|
* using the doorbell register.
|
||||||
@ -4443,8 +4424,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 32; i++)
|
/* Save the PCI command register */
|
||||||
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
|
pci_read_config_word(pdev, 4, &command_register);
|
||||||
|
/* Turn the board off. This is so that later pci_restore_state()
|
||||||
|
* won't turn the board on before the rest of config space is ready.
|
||||||
|
*/
|
||||||
|
pci_disable_device(pdev);
|
||||||
|
pci_save_state(pdev);
|
||||||
|
|
||||||
/* find the first memory BAR, so we can find the cfg table */
|
/* find the first memory BAR, so we can find the cfg table */
|
||||||
rc = cciss_pci_find_memory_BAR(pdev, &paddr);
|
rc = cciss_pci_find_memory_BAR(pdev, &paddr);
|
||||||
@ -4479,26 +4465,32 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
|
|||||||
rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
|
rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto unmap_cfgtable;
|
goto unmap_cfgtable;
|
||||||
|
pci_restore_state(pdev);
|
||||||
/* Restore the PCI configuration space. The Open CISS
|
rc = pci_enable_device(pdev);
|
||||||
* Specification says, "Restore the PCI Configuration
|
if (rc) {
|
||||||
* Registers, offsets 00h through 60h. It is important to
|
dev_warn(&pdev->dev, "failed to enable device.\n");
|
||||||
* restore the command register, 16-bits at offset 04h,
|
goto unmap_cfgtable;
|
||||||
* last. Do not restore the configuration status register,
|
|
||||||
* 16-bits at offset 06h." Note that the offset is 2*i.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
if (i == 2 || i == 3)
|
|
||||||
continue;
|
|
||||||
pci_write_config_word(pdev, 2*i, saved_config_space[i]);
|
|
||||||
}
|
}
|
||||||
wmb();
|
pci_write_config_word(pdev, 4, command_register);
|
||||||
pci_write_config_word(pdev, 4, saved_config_space[2]);
|
|
||||||
|
|
||||||
/* Some devices (notably the HP Smart Array 5i Controller)
|
/* Some devices (notably the HP Smart Array 5i Controller)
|
||||||
need a little pause here */
|
need a little pause here */
|
||||||
msleep(CCISS_POST_RESET_PAUSE_MSECS);
|
msleep(CCISS_POST_RESET_PAUSE_MSECS);
|
||||||
|
|
||||||
|
/* Wait for board to become not ready, then ready. */
|
||||||
|
dev_info(&pdev->dev, "Waiting for board to become ready.\n");
|
||||||
|
rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
|
||||||
|
if (rc) /* Don't bail, might be E500, etc. which can't be reset */
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"failed waiting for board to become not ready\n");
|
||||||
|
rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
|
||||||
|
if (rc) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"failed waiting for board to become ready\n");
|
||||||
|
goto unmap_cfgtable;
|
||||||
|
}
|
||||||
|
dev_info(&pdev->dev, "board ready.\n");
|
||||||
|
|
||||||
/* Controller should be in simple mode at this point. If it's not,
|
/* Controller should be in simple mode at this point. If it's not,
|
||||||
* It means we're on one of those controllers which doesn't support
|
* It means we're on one of those controllers which doesn't support
|
||||||
* the doorbell reset method and on which the PCI power management reset
|
* the doorbell reset method and on which the PCI power management reset
|
||||||
@ -4539,8 +4531,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
|
|||||||
return 0; /* just try to do the kdump anyhow. */
|
return 0; /* just try to do the kdump anyhow. */
|
||||||
if (rc)
|
if (rc)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (cciss_reset_msi(pdev))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* Now try to get the controller to respond to a no-op */
|
/* Now try to get the controller to respond to a no-op */
|
||||||
for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
|
for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
|
||||||
@ -4936,7 +4926,8 @@ static void __exit cciss_cleanup(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
kthread_stop(cciss_scan_thread);
|
kthread_stop(cciss_scan_thread);
|
||||||
remove_proc_entry("driver/cciss", NULL);
|
if (proc_cciss)
|
||||||
|
remove_proc_entry("driver/cciss", NULL);
|
||||||
bus_unregister(&cciss_bus_type);
|
bus_unregister(&cciss_bus_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +200,14 @@ struct ctlr_info
|
|||||||
* the above.
|
* the above.
|
||||||
*/
|
*/
|
||||||
#define CCISS_BOARD_READY_WAIT_SECS (120)
|
#define CCISS_BOARD_READY_WAIT_SECS (120)
|
||||||
|
#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
|
||||||
#define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
|
#define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
|
||||||
#define CCISS_BOARD_READY_ITERATIONS \
|
#define CCISS_BOARD_READY_ITERATIONS \
|
||||||
((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
|
((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
|
||||||
CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
|
CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
|
||||||
|
#define CCISS_BOARD_NOT_READY_ITERATIONS \
|
||||||
|
((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
|
||||||
|
CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
|
||||||
#define CCISS_POST_RESET_PAUSE_MSECS (3000)
|
#define CCISS_POST_RESET_PAUSE_MSECS (3000)
|
||||||
#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
|
#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
|
||||||
#define CCISS_POST_RESET_NOOP_RETRIES (12)
|
#define CCISS_POST_RESET_NOOP_RETRIES (12)
|
||||||
|
@ -78,11 +78,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
|
|||||||
init_completion(&md_io.event);
|
init_completion(&md_io.event);
|
||||||
md_io.error = 0;
|
md_io.error = 0;
|
||||||
|
|
||||||
if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
|
if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
|
||||||
rw |= REQ_HARDBARRIER;
|
rw |= REQ_FUA;
|
||||||
rw |= REQ_UNPLUG | REQ_SYNC;
|
rw |= REQ_UNPLUG | REQ_SYNC;
|
||||||
|
|
||||||
retry:
|
|
||||||
bio = bio_alloc(GFP_NOIO, 1);
|
bio = bio_alloc(GFP_NOIO, 1);
|
||||||
bio->bi_bdev = bdev->md_bdev;
|
bio->bi_bdev = bdev->md_bdev;
|
||||||
bio->bi_sector = sector;
|
bio->bi_sector = sector;
|
||||||
@ -100,17 +99,6 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
|
|||||||
wait_for_completion(&md_io.event);
|
wait_for_completion(&md_io.event);
|
||||||
ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
|
ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
|
||||||
|
|
||||||
/* check for unsupported barrier op.
|
|
||||||
* would rather check on EOPNOTSUPP, but that is not reliable.
|
|
||||||
* don't try again for ANY return value != 0 */
|
|
||||||
if (unlikely((bio->bi_rw & REQ_HARDBARRIER) && !ok)) {
|
|
||||||
/* Try again with no barrier */
|
|
||||||
dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
|
|
||||||
set_bit(MD_NO_BARRIER, &mdev->flags);
|
|
||||||
rw &= ~REQ_HARDBARRIER;
|
|
||||||
bio_put(bio);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
return ok;
|
return ok;
|
||||||
@ -284,18 +272,32 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
|
|||||||
u32 xor_sum = 0;
|
u32 xor_sum = 0;
|
||||||
|
|
||||||
if (!get_ldev(mdev)) {
|
if (!get_ldev(mdev)) {
|
||||||
dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
|
dev_err(DEV,
|
||||||
|
"disk is %s, cannot start al transaction (-%d +%d)\n",
|
||||||
|
drbd_disk_str(mdev->state.disk), evicted, new_enr);
|
||||||
complete(&((struct update_al_work *)w)->event);
|
complete(&((struct update_al_work *)w)->event);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* do we have to do a bitmap write, first?
|
/* do we have to do a bitmap write, first?
|
||||||
* TODO reduce maximum latency:
|
* TODO reduce maximum latency:
|
||||||
* submit both bios, then wait for both,
|
* submit both bios, then wait for both,
|
||||||
* instead of doing two synchronous sector writes. */
|
* instead of doing two synchronous sector writes.
|
||||||
|
* For now, we must not write the transaction,
|
||||||
|
* if we cannot write out the bitmap of the evicted extent. */
|
||||||
if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
|
if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
|
||||||
drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
|
drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
|
||||||
|
|
||||||
mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
|
/* The bitmap write may have failed, causing a state change. */
|
||||||
|
if (mdev->state.disk < D_INCONSISTENT) {
|
||||||
|
dev_err(DEV,
|
||||||
|
"disk is %s, cannot write al transaction (-%d +%d)\n",
|
||||||
|
drbd_disk_str(mdev->state.disk), evicted, new_enr);
|
||||||
|
complete(&((struct update_al_work *)w)->event);
|
||||||
|
put_ldev(mdev);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
|
||||||
buffer = (struct al_transaction *)page_address(mdev->md_io_page);
|
buffer = (struct al_transaction *)page_address(mdev->md_io_page);
|
||||||
|
|
||||||
buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
|
buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
|
||||||
@ -739,7 +741,7 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
|
|||||||
unsigned int enr;
|
unsigned int enr;
|
||||||
unsigned long add = 0;
|
unsigned long add = 0;
|
||||||
char ppb[10];
|
char ppb[10];
|
||||||
int i;
|
int i, tmp;
|
||||||
|
|
||||||
wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
|
wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
|
||||||
|
|
||||||
@ -747,7 +749,9 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
|
|||||||
enr = lc_element_by_index(mdev->act_log, i)->lc_number;
|
enr = lc_element_by_index(mdev->act_log, i)->lc_number;
|
||||||
if (enr == LC_FREE)
|
if (enr == LC_FREE)
|
||||||
continue;
|
continue;
|
||||||
add += drbd_bm_ALe_set_all(mdev, enr);
|
tmp = drbd_bm_ALe_set_all(mdev, enr);
|
||||||
|
dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
|
||||||
|
add += tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
lc_unlock(mdev->act_log);
|
lc_unlock(mdev->act_log);
|
||||||
|
@ -114,11 +114,11 @@ struct drbd_conf;
|
|||||||
#define D_ASSERT(exp) if (!(exp)) \
|
#define D_ASSERT(exp) if (!(exp)) \
|
||||||
dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
|
dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
|
||||||
|
|
||||||
#define ERR_IF(exp) if (({ \
|
#define ERR_IF(exp) if (({ \
|
||||||
int _b = (exp) != 0; \
|
int _b = (exp) != 0; \
|
||||||
if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n", \
|
if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n", \
|
||||||
__func__, #exp, __FILE__, __LINE__); \
|
__func__, #exp, __FILE__, __LINE__); \
|
||||||
_b; \
|
_b; \
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/* Defines to control fault insertion */
|
/* Defines to control fault insertion */
|
||||||
@ -749,17 +749,12 @@ struct drbd_epoch {
|
|||||||
|
|
||||||
/* drbd_epoch flag bits */
|
/* drbd_epoch flag bits */
|
||||||
enum {
|
enum {
|
||||||
DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
|
|
||||||
DE_BARRIER_IN_NEXT_EPOCH_DONE,
|
|
||||||
DE_CONTAINS_A_BARRIER,
|
|
||||||
DE_HAVE_BARRIER_NUMBER,
|
DE_HAVE_BARRIER_NUMBER,
|
||||||
DE_IS_FINISHING,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum epoch_event {
|
enum epoch_event {
|
||||||
EV_PUT,
|
EV_PUT,
|
||||||
EV_GOT_BARRIER_NR,
|
EV_GOT_BARRIER_NR,
|
||||||
EV_BARRIER_DONE,
|
|
||||||
EV_BECAME_LAST,
|
EV_BECAME_LAST,
|
||||||
EV_CLEANUP = 32, /* used as flag */
|
EV_CLEANUP = 32, /* used as flag */
|
||||||
};
|
};
|
||||||
@ -801,11 +796,6 @@ enum {
|
|||||||
__EE_CALL_AL_COMPLETE_IO,
|
__EE_CALL_AL_COMPLETE_IO,
|
||||||
__EE_MAY_SET_IN_SYNC,
|
__EE_MAY_SET_IN_SYNC,
|
||||||
|
|
||||||
/* This epoch entry closes an epoch using a barrier.
|
|
||||||
* On sucessful completion, the epoch is released,
|
|
||||||
* and the P_BARRIER_ACK send. */
|
|
||||||
__EE_IS_BARRIER,
|
|
||||||
|
|
||||||
/* In case a barrier failed,
|
/* In case a barrier failed,
|
||||||
* we need to resubmit without the barrier flag. */
|
* we need to resubmit without the barrier flag. */
|
||||||
__EE_RESUBMITTED,
|
__EE_RESUBMITTED,
|
||||||
@ -820,7 +810,6 @@ enum {
|
|||||||
};
|
};
|
||||||
#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
|
#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
|
||||||
#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC)
|
#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC)
|
||||||
#define EE_IS_BARRIER (1<<__EE_IS_BARRIER)
|
|
||||||
#define EE_RESUBMITTED (1<<__EE_RESUBMITTED)
|
#define EE_RESUBMITTED (1<<__EE_RESUBMITTED)
|
||||||
#define EE_WAS_ERROR (1<<__EE_WAS_ERROR)
|
#define EE_WAS_ERROR (1<<__EE_WAS_ERROR)
|
||||||
#define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST)
|
#define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST)
|
||||||
@ -843,16 +832,15 @@ enum {
|
|||||||
* Gets cleared when the state.conn
|
* Gets cleared when the state.conn
|
||||||
* goes into C_CONNECTED state. */
|
* goes into C_CONNECTED state. */
|
||||||
WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */
|
WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */
|
||||||
NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */
|
|
||||||
CONSIDER_RESYNC,
|
CONSIDER_RESYNC,
|
||||||
|
|
||||||
MD_NO_BARRIER, /* meta data device does not support barriers,
|
MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */
|
||||||
so don't even try */
|
|
||||||
SUSPEND_IO, /* suspend application io */
|
SUSPEND_IO, /* suspend application io */
|
||||||
BITMAP_IO, /* suspend application io;
|
BITMAP_IO, /* suspend application io;
|
||||||
once no more io in flight, start bitmap io */
|
once no more io in flight, start bitmap io */
|
||||||
BITMAP_IO_QUEUED, /* Started bitmap IO */
|
BITMAP_IO_QUEUED, /* Started bitmap IO */
|
||||||
GO_DISKLESS, /* Disk failed, local_cnt reached zero, we are going diskless */
|
GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */
|
||||||
|
WAS_IO_ERROR, /* Local disk failed returned IO error */
|
||||||
RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
|
RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
|
||||||
NET_CONGESTED, /* The data socket is congested */
|
NET_CONGESTED, /* The data socket is congested */
|
||||||
|
|
||||||
@ -947,7 +935,6 @@ enum write_ordering_e {
|
|||||||
WO_none,
|
WO_none,
|
||||||
WO_drain_io,
|
WO_drain_io,
|
||||||
WO_bdev_flush,
|
WO_bdev_flush,
|
||||||
WO_bio_barrier
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fifo_buffer {
|
struct fifo_buffer {
|
||||||
@ -1281,6 +1268,7 @@ extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
|
|||||||
extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
|
extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
|
||||||
extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
|
extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
|
||||||
extern void drbd_go_diskless(struct drbd_conf *mdev);
|
extern void drbd_go_diskless(struct drbd_conf *mdev);
|
||||||
|
extern void drbd_ldev_destroy(struct drbd_conf *mdev);
|
||||||
|
|
||||||
|
|
||||||
/* Meta data layout
|
/* Meta data layout
|
||||||
@ -1798,17 +1786,17 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
|
|||||||
case EP_PASS_ON:
|
case EP_PASS_ON:
|
||||||
if (!forcedetach) {
|
if (!forcedetach) {
|
||||||
if (__ratelimit(&drbd_ratelimit_state))
|
if (__ratelimit(&drbd_ratelimit_state))
|
||||||
dev_err(DEV, "Local IO failed in %s."
|
dev_err(DEV, "Local IO failed in %s.\n", where);
|
||||||
"Passing error on...\n", where);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* NOTE fall through to detach case if forcedetach set */
|
/* NOTE fall through to detach case if forcedetach set */
|
||||||
case EP_DETACH:
|
case EP_DETACH:
|
||||||
case EP_CALL_HELPER:
|
case EP_CALL_HELPER:
|
||||||
|
set_bit(WAS_IO_ERROR, &mdev->flags);
|
||||||
if (mdev->state.disk > D_FAILED) {
|
if (mdev->state.disk > D_FAILED) {
|
||||||
_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
|
_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
|
||||||
dev_err(DEV, "Local IO failed in %s."
|
dev_err(DEV,
|
||||||
"Detaching...\n", where);
|
"Local IO failed in %s. Detaching...\n", where);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1874,7 +1862,7 @@ static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
|
|||||||
static inline sector_t drbd_get_capacity(struct block_device *bdev)
|
static inline sector_t drbd_get_capacity(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
/* return bdev ? get_capacity(bdev->bd_disk) : 0; */
|
/* return bdev ? get_capacity(bdev->bd_disk) : 0; */
|
||||||
return bdev ? bdev->bd_inode->i_size >> 9 : 0;
|
return bdev ? i_size_read(bdev->bd_inode) >> 9 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2127,7 +2115,11 @@ static inline void put_ldev(struct drbd_conf *mdev)
|
|||||||
__release(local);
|
__release(local);
|
||||||
D_ASSERT(i >= 0);
|
D_ASSERT(i >= 0);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
|
if (mdev->state.disk == D_DISKLESS)
|
||||||
|
/* even internal references gone, safe to destroy */
|
||||||
|
drbd_ldev_destroy(mdev);
|
||||||
if (mdev->state.disk == D_FAILED)
|
if (mdev->state.disk == D_FAILED)
|
||||||
|
/* all application IO references gone. */
|
||||||
drbd_go_diskless(mdev);
|
drbd_go_diskless(mdev);
|
||||||
wake_up(&mdev->misc_wait);
|
wake_up(&mdev->misc_wait);
|
||||||
}
|
}
|
||||||
@ -2138,6 +2130,10 @@ static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_stat
|
|||||||
{
|
{
|
||||||
int io_allowed;
|
int io_allowed;
|
||||||
|
|
||||||
|
/* never get a reference while D_DISKLESS */
|
||||||
|
if (mdev->state.disk == D_DISKLESS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
atomic_inc(&mdev->local_cnt);
|
atomic_inc(&mdev->local_cnt);
|
||||||
io_allowed = (mdev->state.disk >= mins);
|
io_allowed = (mdev->state.disk >= mins);
|
||||||
if (!io_allowed)
|
if (!io_allowed)
|
||||||
@ -2406,12 +2402,12 @@ static inline void drbd_md_flush(struct drbd_conf *mdev)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (test_bit(MD_NO_BARRIER, &mdev->flags))
|
if (test_bit(MD_NO_FUA, &mdev->flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
|
r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
|
||||||
if (r) {
|
if (r) {
|
||||||
set_bit(MD_NO_BARRIER, &mdev->flags);
|
set_bit(MD_NO_FUA, &mdev->flags);
|
||||||
dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
|
dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,6 +835,15 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
|
|||||||
ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
|
ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
|
||||||
ns.conn = os.conn;
|
ns.conn = os.conn;
|
||||||
|
|
||||||
|
/* we cannot fail (again) if we already detached */
|
||||||
|
if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
|
||||||
|
ns.disk = D_DISKLESS;
|
||||||
|
|
||||||
|
/* if we are only D_ATTACHING yet,
|
||||||
|
* we can (and should) go directly to D_DISKLESS. */
|
||||||
|
if (ns.disk == D_FAILED && os.disk == D_ATTACHING)
|
||||||
|
ns.disk = D_DISKLESS;
|
||||||
|
|
||||||
/* After C_DISCONNECTING only C_STANDALONE may follow */
|
/* After C_DISCONNECTING only C_STANDALONE may follow */
|
||||||
if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
|
if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
|
||||||
ns.conn = os.conn;
|
ns.conn = os.conn;
|
||||||
@ -1056,7 +1065,15 @@ int __drbd_set_state(struct drbd_conf *mdev,
|
|||||||
!test_and_set_bit(CONFIG_PENDING, &mdev->flags))
|
!test_and_set_bit(CONFIG_PENDING, &mdev->flags))
|
||||||
set_bit(DEVICE_DYING, &mdev->flags);
|
set_bit(DEVICE_DYING, &mdev->flags);
|
||||||
|
|
||||||
mdev->state.i = ns.i;
|
/* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
|
||||||
|
* on the ldev here, to be sure the transition -> D_DISKLESS resp.
|
||||||
|
* drbd_ldev_destroy() won't happen before our corresponding
|
||||||
|
* after_state_ch works run, where we put_ldev again. */
|
||||||
|
if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
|
||||||
|
(os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
|
||||||
|
atomic_inc(&mdev->local_cnt);
|
||||||
|
|
||||||
|
mdev->state = ns;
|
||||||
wake_up(&mdev->misc_wait);
|
wake_up(&mdev->misc_wait);
|
||||||
wake_up(&mdev->state_wait);
|
wake_up(&mdev->state_wait);
|
||||||
|
|
||||||
@ -1268,7 +1285,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
|||||||
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
|
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
|
||||||
drbd_uuid_new_current(mdev);
|
drbd_uuid_new_current(mdev);
|
||||||
clear_bit(NEW_CUR_UUID, &mdev->flags);
|
clear_bit(NEW_CUR_UUID, &mdev->flags);
|
||||||
drbd_md_sync(mdev);
|
|
||||||
}
|
}
|
||||||
spin_lock_irq(&mdev->req_lock);
|
spin_lock_irq(&mdev->req_lock);
|
||||||
_drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
|
_drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
|
||||||
@ -1365,63 +1381,64 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
|||||||
os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
|
os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
|
||||||
drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
|
drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
|
||||||
|
|
||||||
/* first half of local IO error */
|
/* first half of local IO error, failure to attach,
|
||||||
if (os.disk > D_FAILED && ns.disk == D_FAILED) {
|
* or administrative detach */
|
||||||
enum drbd_io_error_p eh = EP_PASS_ON;
|
if (os.disk != D_FAILED && ns.disk == D_FAILED) {
|
||||||
|
enum drbd_io_error_p eh;
|
||||||
|
int was_io_error;
|
||||||
|
/* corresponding get_ldev was in __drbd_set_state, to serialize
|
||||||
|
* our cleanup here with the transition to D_DISKLESS,
|
||||||
|
* so it is safe to dreference ldev here. */
|
||||||
|
eh = mdev->ldev->dc.on_io_error;
|
||||||
|
was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
|
||||||
|
|
||||||
|
/* current state still has to be D_FAILED,
|
||||||
|
* there is only one way out: to D_DISKLESS,
|
||||||
|
* and that may only happen after our put_ldev below. */
|
||||||
|
if (mdev->state.disk != D_FAILED)
|
||||||
|
dev_err(DEV,
|
||||||
|
"ASSERT FAILED: disk is %s during detach\n",
|
||||||
|
drbd_disk_str(mdev->state.disk));
|
||||||
|
|
||||||
if (drbd_send_state(mdev))
|
if (drbd_send_state(mdev))
|
||||||
dev_warn(DEV, "Notified peer that my disk is broken.\n");
|
dev_warn(DEV, "Notified peer that I am detaching my disk\n");
|
||||||
else
|
else
|
||||||
dev_err(DEV, "Sending state for drbd_io_error() failed\n");
|
dev_err(DEV, "Sending state for detaching disk failed\n");
|
||||||
|
|
||||||
drbd_rs_cancel_all(mdev);
|
drbd_rs_cancel_all(mdev);
|
||||||
|
|
||||||
if (get_ldev_if_state(mdev, D_FAILED)) {
|
/* In case we want to get something to stable storage still,
|
||||||
eh = mdev->ldev->dc.on_io_error;
|
* this may be the last chance.
|
||||||
put_ldev(mdev);
|
* Following put_ldev may transition to D_DISKLESS. */
|
||||||
}
|
drbd_md_sync(mdev);
|
||||||
if (eh == EP_CALL_HELPER)
|
put_ldev(mdev);
|
||||||
|
|
||||||
|
if (was_io_error && eh == EP_CALL_HELPER)
|
||||||
drbd_khelper(mdev, "local-io-error");
|
drbd_khelper(mdev, "local-io-error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* second half of local IO error, failure to attach,
|
||||||
|
* or administrative detach,
|
||||||
|
* after local_cnt references have reached zero again */
|
||||||
|
if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
|
||||||
|
/* We must still be diskless,
|
||||||
|
* re-attach has to be serialized with this! */
|
||||||
|
if (mdev->state.disk != D_DISKLESS)
|
||||||
|
dev_err(DEV,
|
||||||
|
"ASSERT FAILED: disk is %s while going diskless\n",
|
||||||
|
drbd_disk_str(mdev->state.disk));
|
||||||
|
|
||||||
/* second half of local IO error handling,
|
mdev->rs_total = 0;
|
||||||
* after local_cnt references have reached zero: */
|
mdev->rs_failed = 0;
|
||||||
if (os.disk == D_FAILED && ns.disk == D_DISKLESS) {
|
atomic_set(&mdev->rs_pending_cnt, 0);
|
||||||
mdev->rs_total = 0;
|
|
||||||
mdev->rs_failed = 0;
|
|
||||||
atomic_set(&mdev->rs_pending_cnt, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
|
|
||||||
/* We must still be diskless,
|
|
||||||
* re-attach has to be serialized with this! */
|
|
||||||
if (mdev->state.disk != D_DISKLESS)
|
|
||||||
dev_err(DEV,
|
|
||||||
"ASSERT FAILED: disk is %s while going diskless\n",
|
|
||||||
drbd_disk_str(mdev->state.disk));
|
|
||||||
|
|
||||||
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state
|
|
||||||
* will inc/dec it frequently. Since we became D_DISKLESS, no
|
|
||||||
* one has touched the protected members anymore, though, so we
|
|
||||||
* are safe to free them here. */
|
|
||||||
if (drbd_send_state(mdev))
|
if (drbd_send_state(mdev))
|
||||||
dev_warn(DEV, "Notified peer that I detached my disk.\n");
|
dev_warn(DEV, "Notified peer that I'm now diskless.\n");
|
||||||
else
|
else
|
||||||
dev_err(DEV, "Sending state for detach failed\n");
|
dev_err(DEV, "Sending state for being diskless failed\n");
|
||||||
|
/* corresponding get_ldev in __drbd_set_state
|
||||||
lc_destroy(mdev->resync);
|
* this may finaly trigger drbd_ldev_destroy. */
|
||||||
mdev->resync = NULL;
|
put_ldev(mdev);
|
||||||
lc_destroy(mdev->act_log);
|
|
||||||
mdev->act_log = NULL;
|
|
||||||
__no_warn(local,
|
|
||||||
drbd_free_bc(mdev->ldev);
|
|
||||||
mdev->ldev = NULL;);
|
|
||||||
|
|
||||||
if (mdev->md_io_tmpp) {
|
|
||||||
__free_page(mdev->md_io_tmpp);
|
|
||||||
mdev->md_io_tmpp = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disks got bigger while they were detached */
|
/* Disks got bigger while they were detached */
|
||||||
@ -2772,11 +2789,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
|
|||||||
|
|
||||||
drbd_set_defaults(mdev);
|
drbd_set_defaults(mdev);
|
||||||
|
|
||||||
/* for now, we do NOT yet support it,
|
|
||||||
* even though we start some framework
|
|
||||||
* to eventually support barriers */
|
|
||||||
set_bit(NO_BARRIER_SUPP, &mdev->flags);
|
|
||||||
|
|
||||||
atomic_set(&mdev->ap_bio_cnt, 0);
|
atomic_set(&mdev->ap_bio_cnt, 0);
|
||||||
atomic_set(&mdev->ap_pending_cnt, 0);
|
atomic_set(&mdev->ap_pending_cnt, 0);
|
||||||
atomic_set(&mdev->rs_pending_cnt, 0);
|
atomic_set(&mdev->rs_pending_cnt, 0);
|
||||||
@ -2842,7 +2854,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
|
|||||||
drbd_thread_init(mdev, &mdev->asender, drbd_asender);
|
drbd_thread_init(mdev, &mdev->asender, drbd_asender);
|
||||||
|
|
||||||
mdev->agreed_pro_version = PRO_VERSION_MAX;
|
mdev->agreed_pro_version = PRO_VERSION_MAX;
|
||||||
mdev->write_ordering = WO_bio_barrier;
|
mdev->write_ordering = WO_bdev_flush;
|
||||||
mdev->resync_wenr = LC_FREE;
|
mdev->resync_wenr = LC_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2899,7 +2911,6 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev)
|
|||||||
D_ASSERT(list_empty(&mdev->resync_work.list));
|
D_ASSERT(list_empty(&mdev->resync_work.list));
|
||||||
D_ASSERT(list_empty(&mdev->unplug_work.list));
|
D_ASSERT(list_empty(&mdev->unplug_work.list));
|
||||||
D_ASSERT(list_empty(&mdev->go_diskless.list));
|
D_ASSERT(list_empty(&mdev->go_diskless.list));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3660,6 +3671,8 @@ void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
|
|||||||
|
|
||||||
get_random_bytes(&val, sizeof(u64));
|
get_random_bytes(&val, sizeof(u64));
|
||||||
_drbd_uuid_set(mdev, UI_CURRENT, val);
|
_drbd_uuid_set(mdev, UI_CURRENT, val);
|
||||||
|
/* get it to stable storage _now_ */
|
||||||
|
drbd_md_sync(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
|
void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
|
||||||
@ -3756,19 +3769,31 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drbd_ldev_destroy(struct drbd_conf *mdev)
|
||||||
|
{
|
||||||
|
lc_destroy(mdev->resync);
|
||||||
|
mdev->resync = NULL;
|
||||||
|
lc_destroy(mdev->act_log);
|
||||||
|
mdev->act_log = NULL;
|
||||||
|
__no_warn(local,
|
||||||
|
drbd_free_bc(mdev->ldev);
|
||||||
|
mdev->ldev = NULL;);
|
||||||
|
|
||||||
|
if (mdev->md_io_tmpp) {
|
||||||
|
__free_page(mdev->md_io_tmpp);
|
||||||
|
mdev->md_io_tmpp = NULL;
|
||||||
|
}
|
||||||
|
clear_bit(GO_DISKLESS, &mdev->flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
|
static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
|
||||||
{
|
{
|
||||||
D_ASSERT(mdev->state.disk == D_FAILED);
|
D_ASSERT(mdev->state.disk == D_FAILED);
|
||||||
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
|
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
|
||||||
* inc/dec it frequently. Once we are D_DISKLESS, no one will touch
|
* inc/dec it frequently. Once we are D_DISKLESS, no one will touch
|
||||||
* the protected members anymore, though, so in the after_state_ch work
|
* the protected members anymore, though, so once put_ldev reaches zero
|
||||||
* it will be safe to free them. */
|
* again, it will be safe to free them. */
|
||||||
drbd_force_state(mdev, NS(disk, D_DISKLESS));
|
drbd_force_state(mdev, NS(disk, D_DISKLESS));
|
||||||
/* We need to wait for return of references checked out while we still
|
|
||||||
* have been D_FAILED, though (drbd_md_sync, bitmap io). */
|
|
||||||
wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
|
|
||||||
|
|
||||||
clear_bit(GO_DISKLESS, &mdev->flags);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3777,9 +3802,6 @@ void drbd_go_diskless(struct drbd_conf *mdev)
|
|||||||
D_ASSERT(mdev->state.disk == D_FAILED);
|
D_ASSERT(mdev->state.disk == D_FAILED);
|
||||||
if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
|
if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
|
||||||
drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
|
drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
|
||||||
/* don't drbd_queue_work_front,
|
|
||||||
* we need to serialize with the after_state_ch work
|
|
||||||
* of the -> D_FAILED transition. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -870,6 +870,11 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
retcode = ERR_DISK_CONFIGURED;
|
retcode = ERR_DISK_CONFIGURED;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
/* It may just now have detached because of IO error. Make sure
|
||||||
|
* drbd_ldev_destroy is done already, we may end up here very fast,
|
||||||
|
* e.g. if someone calls attach from the on-io-error handler,
|
||||||
|
* to realize a "hot spare" feature (not that I'd recommend that) */
|
||||||
|
wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
|
||||||
|
|
||||||
/* allocation not in the IO path, cqueue thread context */
|
/* allocation not in the IO path, cqueue thread context */
|
||||||
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
|
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
|
||||||
@ -1098,9 +1103,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
/* Reset the "barriers don't work" bits here, then force meta data to
|
/* Reset the "barriers don't work" bits here, then force meta data to
|
||||||
* be written, to ensure we determine if barriers are supported. */
|
* be written, to ensure we determine if barriers are supported. */
|
||||||
if (nbc->dc.no_md_flush)
|
if (nbc->dc.no_md_flush)
|
||||||
set_bit(MD_NO_BARRIER, &mdev->flags);
|
set_bit(MD_NO_FUA, &mdev->flags);
|
||||||
else
|
else
|
||||||
clear_bit(MD_NO_BARRIER, &mdev->flags);
|
clear_bit(MD_NO_FUA, &mdev->flags);
|
||||||
|
|
||||||
/* Point of no return reached.
|
/* Point of no return reached.
|
||||||
* Devices and memory are no longer released by error cleanup below.
|
* Devices and memory are no longer released by error cleanup below.
|
||||||
@ -1112,8 +1117,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
nbc = NULL;
|
nbc = NULL;
|
||||||
resync_lru = NULL;
|
resync_lru = NULL;
|
||||||
|
|
||||||
mdev->write_ordering = WO_bio_barrier;
|
mdev->write_ordering = WO_bdev_flush;
|
||||||
drbd_bump_write_ordering(mdev, WO_bio_barrier);
|
drbd_bump_write_ordering(mdev, WO_bdev_flush);
|
||||||
|
|
||||||
if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
|
if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
|
||||||
set_bit(CRASHED_PRIMARY, &mdev->flags);
|
set_bit(CRASHED_PRIMARY, &mdev->flags);
|
||||||
@ -1262,7 +1267,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
force_diskless_dec:
|
force_diskless_dec:
|
||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
force_diskless:
|
force_diskless:
|
||||||
drbd_force_state(mdev, NS(disk, D_DISKLESS));
|
drbd_force_state(mdev, NS(disk, D_FAILED));
|
||||||
drbd_md_sync(mdev);
|
drbd_md_sync(mdev);
|
||||||
release_bdev2_fail:
|
release_bdev2_fail:
|
||||||
if (nbc)
|
if (nbc)
|
||||||
@ -1285,10 +1290,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detaching the disk is a process in multiple stages. First we need to lock
|
||||||
|
* out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
|
||||||
|
* Then we transition to D_DISKLESS, and wait for put_ldev() to return all
|
||||||
|
* internal references as well.
|
||||||
|
* Only then we have finally detached. */
|
||||||
static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
|
static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
|
||||||
struct drbd_nl_cfg_reply *reply)
|
struct drbd_nl_cfg_reply *reply)
|
||||||
{
|
{
|
||||||
|
drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
|
||||||
reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
|
reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
|
||||||
|
if (mdev->state.disk == D_DISKLESS)
|
||||||
|
wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
|
||||||
|
drbd_resume_io(mdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1953,7 +1967,6 @@ static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
|||||||
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
|
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
|
||||||
drbd_uuid_new_current(mdev);
|
drbd_uuid_new_current(mdev);
|
||||||
clear_bit(NEW_CUR_UUID, &mdev->flags);
|
clear_bit(NEW_CUR_UUID, &mdev->flags);
|
||||||
drbd_md_sync(mdev);
|
|
||||||
}
|
}
|
||||||
drbd_suspend_io(mdev);
|
drbd_suspend_io(mdev);
|
||||||
reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
|
reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
|
||||||
|
@ -158,7 +158,6 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
|||||||
[WO_none] = 'n',
|
[WO_none] = 'n',
|
||||||
[WO_drain_io] = 'd',
|
[WO_drain_io] = 'd',
|
||||||
[WO_bdev_flush] = 'f',
|
[WO_bdev_flush] = 'f',
|
||||||
[WO_bio_barrier] = 'b',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
|
seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
|
||||||
|
@ -49,11 +49,6 @@
|
|||||||
|
|
||||||
#include "drbd_vli.h"
|
#include "drbd_vli.h"
|
||||||
|
|
||||||
struct flush_work {
|
|
||||||
struct drbd_work w;
|
|
||||||
struct drbd_epoch *epoch;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum finish_epoch {
|
enum finish_epoch {
|
||||||
FE_STILL_LIVE,
|
FE_STILL_LIVE,
|
||||||
FE_DESTROYED,
|
FE_DESTROYED,
|
||||||
@ -66,16 +61,6 @@ static int drbd_do_auth(struct drbd_conf *mdev);
|
|||||||
static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
|
static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
|
||||||
static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
|
static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
|
||||||
|
|
||||||
static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
|
|
||||||
{
|
|
||||||
struct drbd_epoch *prev;
|
|
||||||
spin_lock(&mdev->epoch_lock);
|
|
||||||
prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
|
|
||||||
if (prev == epoch || prev == mdev->current_epoch)
|
|
||||||
prev = NULL;
|
|
||||||
spin_unlock(&mdev->epoch_lock);
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
|
#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
|
||||||
|
|
||||||
@ -981,7 +966,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
|
static void drbd_flush(struct drbd_conf *mdev)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@ -997,24 +982,6 @@ static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct d
|
|||||||
}
|
}
|
||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
|
|
||||||
{
|
|
||||||
struct flush_work *fw = (struct flush_work *)w;
|
|
||||||
struct drbd_epoch *epoch = fw->epoch;
|
|
||||||
|
|
||||||
kfree(w);
|
|
||||||
|
|
||||||
if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
|
|
||||||
drbd_flush_after_epoch(mdev, epoch);
|
|
||||||
|
|
||||||
drbd_may_finish_epoch(mdev, epoch, EV_PUT |
|
|
||||||
(mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1027,15 +994,13 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
|
|||||||
struct drbd_epoch *epoch,
|
struct drbd_epoch *epoch,
|
||||||
enum epoch_event ev)
|
enum epoch_event ev)
|
||||||
{
|
{
|
||||||
int finish, epoch_size;
|
int epoch_size;
|
||||||
struct drbd_epoch *next_epoch;
|
struct drbd_epoch *next_epoch;
|
||||||
int schedule_flush = 0;
|
|
||||||
enum finish_epoch rv = FE_STILL_LIVE;
|
enum finish_epoch rv = FE_STILL_LIVE;
|
||||||
|
|
||||||
spin_lock(&mdev->epoch_lock);
|
spin_lock(&mdev->epoch_lock);
|
||||||
do {
|
do {
|
||||||
next_epoch = NULL;
|
next_epoch = NULL;
|
||||||
finish = 0;
|
|
||||||
|
|
||||||
epoch_size = atomic_read(&epoch->epoch_size);
|
epoch_size = atomic_read(&epoch->epoch_size);
|
||||||
|
|
||||||
@ -1045,16 +1010,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
|
|||||||
break;
|
break;
|
||||||
case EV_GOT_BARRIER_NR:
|
case EV_GOT_BARRIER_NR:
|
||||||
set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
|
set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
|
||||||
|
|
||||||
/* Special case: If we just switched from WO_bio_barrier to
|
|
||||||
WO_bdev_flush we should not finish the current epoch */
|
|
||||||
if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
|
|
||||||
mdev->write_ordering != WO_bio_barrier &&
|
|
||||||
epoch == mdev->current_epoch)
|
|
||||||
clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
|
|
||||||
break;
|
|
||||||
case EV_BARRIER_DONE:
|
|
||||||
set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
|
|
||||||
break;
|
break;
|
||||||
case EV_BECAME_LAST:
|
case EV_BECAME_LAST:
|
||||||
/* nothing to do*/
|
/* nothing to do*/
|
||||||
@ -1063,23 +1018,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
|
|||||||
|
|
||||||
if (epoch_size != 0 &&
|
if (epoch_size != 0 &&
|
||||||
atomic_read(&epoch->active) == 0 &&
|
atomic_read(&epoch->active) == 0 &&
|
||||||
test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
|
test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) {
|
||||||
epoch->list.prev == &mdev->current_epoch->list &&
|
|
||||||
!test_bit(DE_IS_FINISHING, &epoch->flags)) {
|
|
||||||
/* Nearly all conditions are met to finish that epoch... */
|
|
||||||
if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
|
|
||||||
mdev->write_ordering == WO_none ||
|
|
||||||
(epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
|
|
||||||
ev & EV_CLEANUP) {
|
|
||||||
finish = 1;
|
|
||||||
set_bit(DE_IS_FINISHING, &epoch->flags);
|
|
||||||
} else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
|
|
||||||
mdev->write_ordering == WO_bio_barrier) {
|
|
||||||
atomic_inc(&epoch->active);
|
|
||||||
schedule_flush = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finish) {
|
|
||||||
if (!(ev & EV_CLEANUP)) {
|
if (!(ev & EV_CLEANUP)) {
|
||||||
spin_unlock(&mdev->epoch_lock);
|
spin_unlock(&mdev->epoch_lock);
|
||||||
drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
|
drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
|
||||||
@ -1102,6 +1041,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
|
|||||||
/* atomic_set(&epoch->active, 0); is already zero */
|
/* atomic_set(&epoch->active, 0); is already zero */
|
||||||
if (rv == FE_STILL_LIVE)
|
if (rv == FE_STILL_LIVE)
|
||||||
rv = FE_RECYCLED;
|
rv = FE_RECYCLED;
|
||||||
|
wake_up(&mdev->ee_wait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1113,22 +1053,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
|
|||||||
|
|
||||||
spin_unlock(&mdev->epoch_lock);
|
spin_unlock(&mdev->epoch_lock);
|
||||||
|
|
||||||
if (schedule_flush) {
|
|
||||||
struct flush_work *fw;
|
|
||||||
fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
|
|
||||||
if (fw) {
|
|
||||||
fw->w.cb = w_flush;
|
|
||||||
fw->epoch = epoch;
|
|
||||||
drbd_queue_work(&mdev->data.work, &fw->w);
|
|
||||||
} else {
|
|
||||||
dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
|
|
||||||
set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
|
|
||||||
/* That is not a recursion, only one level */
|
|
||||||
drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
|
|
||||||
drbd_may_finish_epoch(mdev, epoch, EV_PUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,19 +1068,16 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo)
|
|||||||
[WO_none] = "none",
|
[WO_none] = "none",
|
||||||
[WO_drain_io] = "drain",
|
[WO_drain_io] = "drain",
|
||||||
[WO_bdev_flush] = "flush",
|
[WO_bdev_flush] = "flush",
|
||||||
[WO_bio_barrier] = "barrier",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pwo = mdev->write_ordering;
|
pwo = mdev->write_ordering;
|
||||||
wo = min(pwo, wo);
|
wo = min(pwo, wo);
|
||||||
if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
|
|
||||||
wo = WO_bdev_flush;
|
|
||||||
if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
|
if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
|
||||||
wo = WO_drain_io;
|
wo = WO_drain_io;
|
||||||
if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
|
if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
|
||||||
wo = WO_none;
|
wo = WO_none;
|
||||||
mdev->write_ordering = wo;
|
mdev->write_ordering = wo;
|
||||||
if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
|
if (pwo != mdev->write_ordering || wo == WO_bdev_flush)
|
||||||
dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
|
dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,7 +1113,7 @@ next_bio:
|
|||||||
bio->bi_sector = sector;
|
bio->bi_sector = sector;
|
||||||
bio->bi_bdev = mdev->ldev->backing_bdev;
|
bio->bi_bdev = mdev->ldev->backing_bdev;
|
||||||
/* we special case some flags in the multi-bio case, see below
|
/* we special case some flags in the multi-bio case, see below
|
||||||
* (REQ_UNPLUG, REQ_HARDBARRIER) */
|
* (REQ_UNPLUG) */
|
||||||
bio->bi_rw = rw;
|
bio->bi_rw = rw;
|
||||||
bio->bi_private = e;
|
bio->bi_private = e;
|
||||||
bio->bi_end_io = drbd_endio_sec;
|
bio->bi_end_io = drbd_endio_sec;
|
||||||
@ -1226,11 +1147,6 @@ next_bio:
|
|||||||
bio->bi_rw &= ~REQ_UNPLUG;
|
bio->bi_rw &= ~REQ_UNPLUG;
|
||||||
|
|
||||||
drbd_generic_make_request(mdev, fault_type, bio);
|
drbd_generic_make_request(mdev, fault_type, bio);
|
||||||
|
|
||||||
/* strip off REQ_HARDBARRIER,
|
|
||||||
* unless it is the first or last bio */
|
|
||||||
if (bios && bios->bi_next)
|
|
||||||
bios->bi_rw &= ~REQ_HARDBARRIER;
|
|
||||||
} while (bios);
|
} while (bios);
|
||||||
maybe_kick_lo(mdev);
|
maybe_kick_lo(mdev);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1244,45 +1160,9 @@ fail:
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* w_e_reissue() - Worker callback; Resubmit a bio, without REQ_HARDBARRIER set
|
|
||||||
* @mdev: DRBD device.
|
|
||||||
* @w: work object.
|
|
||||||
* @cancel: The connection will be closed anyways (unused in this callback)
|
|
||||||
*/
|
|
||||||
int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
|
|
||||||
{
|
|
||||||
struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
|
|
||||||
/* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
|
|
||||||
(and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
|
|
||||||
so that we can finish that epoch in drbd_may_finish_epoch().
|
|
||||||
That is necessary if we already have a long chain of Epochs, before
|
|
||||||
we realize that REQ_HARDBARRIER is actually not supported */
|
|
||||||
|
|
||||||
/* As long as the -ENOTSUPP on the barrier is reported immediately
|
|
||||||
that will never trigger. If it is reported late, we will just
|
|
||||||
print that warning and continue correctly for all future requests
|
|
||||||
with WO_bdev_flush */
|
|
||||||
if (previous_epoch(mdev, e->epoch))
|
|
||||||
dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
|
|
||||||
|
|
||||||
/* we still have a local reference,
|
|
||||||
* get_ldev was done in receive_Data. */
|
|
||||||
|
|
||||||
e->w.cb = e_end_block;
|
|
||||||
if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_DT_WR) != 0) {
|
|
||||||
/* drbd_submit_ee fails for one reason only:
|
|
||||||
* if was not able to allocate sufficient bios.
|
|
||||||
* requeue, try again later. */
|
|
||||||
e->w.cb = w_e_reissue;
|
|
||||||
drbd_queue_work(&mdev->data.work, &e->w);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||||
{
|
{
|
||||||
int rv, issue_flush;
|
int rv;
|
||||||
struct p_barrier *p = &mdev->data.rbuf.barrier;
|
struct p_barrier *p = &mdev->data.rbuf.barrier;
|
||||||
struct drbd_epoch *epoch;
|
struct drbd_epoch *epoch;
|
||||||
|
|
||||||
@ -1300,44 +1180,40 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign
|
|||||||
* Therefore we must send the barrier_ack after the barrier request was
|
* Therefore we must send the barrier_ack after the barrier request was
|
||||||
* completed. */
|
* completed. */
|
||||||
switch (mdev->write_ordering) {
|
switch (mdev->write_ordering) {
|
||||||
case WO_bio_barrier:
|
|
||||||
case WO_none:
|
case WO_none:
|
||||||
if (rv == FE_RECYCLED)
|
if (rv == FE_RECYCLED)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
break;
|
|
||||||
|
/* receiver context, in the writeout path of the other node.
|
||||||
|
* avoid potential distributed deadlock */
|
||||||
|
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
|
||||||
|
if (epoch)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
case WO_bdev_flush:
|
case WO_bdev_flush:
|
||||||
case WO_drain_io:
|
case WO_drain_io:
|
||||||
if (rv == FE_STILL_LIVE) {
|
|
||||||
set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
|
|
||||||
drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
|
|
||||||
rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
|
|
||||||
}
|
|
||||||
if (rv == FE_RECYCLED)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* The asender will send all the ACKs and barrier ACKs out, since
|
|
||||||
all EEs moved from the active_ee to the done_ee. We need to
|
|
||||||
provide a new epoch object for the EEs that come in soon */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* receiver context, in the writeout path of the other node.
|
|
||||||
* avoid potential distributed deadlock */
|
|
||||||
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
|
|
||||||
if (!epoch) {
|
|
||||||
dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
|
|
||||||
issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
|
|
||||||
drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
|
drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
|
||||||
if (issue_flush) {
|
drbd_flush(mdev);
|
||||||
rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
|
|
||||||
if (rv == FE_RECYCLED)
|
if (atomic_read(&mdev->current_epoch->epoch_size)) {
|
||||||
return TRUE;
|
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
|
||||||
|
if (epoch)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
|
epoch = mdev->current_epoch;
|
||||||
|
wait_event(mdev->ee_wait, atomic_read(&epoch->epoch_size) == 0);
|
||||||
|
|
||||||
|
D_ASSERT(atomic_read(&epoch->active) == 0);
|
||||||
|
D_ASSERT(epoch->flags == 0);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
default:
|
||||||
|
dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
epoch->flags = 0;
|
epoch->flags = 0;
|
||||||
@ -1652,15 +1528,8 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
|
|||||||
{
|
{
|
||||||
struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
|
struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
|
||||||
sector_t sector = e->sector;
|
sector_t sector = e->sector;
|
||||||
struct drbd_epoch *epoch;
|
|
||||||
int ok = 1, pcmd;
|
int ok = 1, pcmd;
|
||||||
|
|
||||||
if (e->flags & EE_IS_BARRIER) {
|
|
||||||
epoch = previous_epoch(mdev, e->epoch);
|
|
||||||
if (epoch)
|
|
||||||
drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
|
if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
|
||||||
if (likely((e->flags & EE_WAS_ERROR) == 0)) {
|
if (likely((e->flags & EE_WAS_ERROR) == 0)) {
|
||||||
pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
|
pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
|
||||||
@ -1817,27 +1686,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
|
|||||||
e->epoch = mdev->current_epoch;
|
e->epoch = mdev->current_epoch;
|
||||||
atomic_inc(&e->epoch->epoch_size);
|
atomic_inc(&e->epoch->epoch_size);
|
||||||
atomic_inc(&e->epoch->active);
|
atomic_inc(&e->epoch->active);
|
||||||
|
|
||||||
if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
|
|
||||||
struct drbd_epoch *epoch;
|
|
||||||
/* Issue a barrier if we start a new epoch, and the previous epoch
|
|
||||||
was not a epoch containing a single request which already was
|
|
||||||
a Barrier. */
|
|
||||||
epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
|
|
||||||
if (epoch == e->epoch) {
|
|
||||||
set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
|
|
||||||
rw |= REQ_HARDBARRIER;
|
|
||||||
e->flags |= EE_IS_BARRIER;
|
|
||||||
} else {
|
|
||||||
if (atomic_read(&epoch->epoch_size) > 1 ||
|
|
||||||
!test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
|
|
||||||
set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
|
|
||||||
set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
|
|
||||||
rw |= REQ_HARDBARRIER;
|
|
||||||
e->flags |= EE_IS_BARRIER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock(&mdev->epoch_lock);
|
spin_unlock(&mdev->epoch_lock);
|
||||||
|
|
||||||
dp_flags = be32_to_cpu(p->dp_flags);
|
dp_flags = be32_to_cpu(p->dp_flags);
|
||||||
@ -1995,10 +1843,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mdev->state.pdsk == D_DISKLESS) {
|
if (mdev->state.pdsk < D_INCONSISTENT) {
|
||||||
/* In case we have the only disk of the cluster, */
|
/* In case we have the only disk of the cluster, */
|
||||||
drbd_set_out_of_sync(mdev, e->sector, e->size);
|
drbd_set_out_of_sync(mdev, e->sector, e->size);
|
||||||
e->flags |= EE_CALL_AL_COMPLETE_IO;
|
e->flags |= EE_CALL_AL_COMPLETE_IO;
|
||||||
|
e->flags &= ~EE_MAY_SET_IN_SYNC;
|
||||||
drbd_al_begin_io(mdev, e->sector);
|
drbd_al_begin_io(mdev, e->sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3362,7 +3211,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
|
|||||||
if (ns.conn == C_MASK) {
|
if (ns.conn == C_MASK) {
|
||||||
ns.conn = C_CONNECTED;
|
ns.conn = C_CONNECTED;
|
||||||
if (mdev->state.disk == D_NEGOTIATING) {
|
if (mdev->state.disk == D_NEGOTIATING) {
|
||||||
drbd_force_state(mdev, NS(disk, D_DISKLESS));
|
drbd_force_state(mdev, NS(disk, D_FAILED));
|
||||||
} else if (peer_state.disk == D_NEGOTIATING) {
|
} else if (peer_state.disk == D_NEGOTIATING) {
|
||||||
dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
|
dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
|
||||||
peer_state.disk = D_DISKLESS;
|
peer_state.disk = D_DISKLESS;
|
||||||
|
@ -258,7 +258,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
|
|||||||
if (!hlist_unhashed(&req->colision))
|
if (!hlist_unhashed(&req->colision))
|
||||||
hlist_del(&req->colision);
|
hlist_del(&req->colision);
|
||||||
else
|
else
|
||||||
D_ASSERT((s & RQ_NET_MASK) == 0);
|
D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
|
||||||
|
|
||||||
/* for writes we need to do some extra housekeeping */
|
/* for writes we need to do some extra housekeeping */
|
||||||
if (rw == WRITE)
|
if (rw == WRITE)
|
||||||
@ -813,7 +813,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
|
|||||||
mdev->state.conn >= C_CONNECTED));
|
mdev->state.conn >= C_CONNECTED));
|
||||||
|
|
||||||
if (!(local || remote) && !is_susp(mdev->state)) {
|
if (!(local || remote) && !is_susp(mdev->state)) {
|
||||||
dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
|
if (__ratelimit(&drbd_ratelimit_state))
|
||||||
|
dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
|
||||||
goto fail_free_complete;
|
goto fail_free_complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -942,12 +943,21 @@ allocate_barrier:
|
|||||||
if (local) {
|
if (local) {
|
||||||
req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
|
req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
|
||||||
|
|
||||||
if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
|
/* State may have changed since we grabbed our reference on the
|
||||||
: rw == READ ? DRBD_FAULT_DT_RD
|
* mdev->ldev member. Double check, and short-circuit to endio.
|
||||||
: DRBD_FAULT_DT_RA))
|
* In case the last activity log transaction failed to get on
|
||||||
|
* stable storage, and this is a WRITE, we may not even submit
|
||||||
|
* this bio. */
|
||||||
|
if (get_ldev(mdev)) {
|
||||||
|
if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
|
||||||
|
: rw == READ ? DRBD_FAULT_DT_RD
|
||||||
|
: DRBD_FAULT_DT_RA))
|
||||||
|
bio_endio(req->private_bio, -EIO);
|
||||||
|
else
|
||||||
|
generic_make_request(req->private_bio);
|
||||||
|
put_ldev(mdev);
|
||||||
|
} else
|
||||||
bio_endio(req->private_bio, -EIO);
|
bio_endio(req->private_bio, -EIO);
|
||||||
else
|
|
||||||
generic_make_request(req->private_bio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we need to plug ALWAYS since we possibly need to kick lo_dev.
|
/* we need to plug ALWAYS since we possibly need to kick lo_dev.
|
||||||
@ -1022,20 +1032,6 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reject barrier requests if we know the underlying device does
|
|
||||||
* not support them.
|
|
||||||
* XXX: Need to get this info from peer as well some how so we
|
|
||||||
* XXX: reject if EITHER side/data/metadata area does not support them.
|
|
||||||
*
|
|
||||||
* because of those XXX, this is not yet enabled,
|
|
||||||
* i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
|
|
||||||
*/
|
|
||||||
if (unlikely(bio->bi_rw & REQ_HARDBARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags)) {
|
|
||||||
/* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
|
|
||||||
bio_endio(bio, -EOPNOTSUPP);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* what we "blindly" assume:
|
* what we "blindly" assume:
|
||||||
*/
|
*/
|
||||||
|
@ -102,12 +102,6 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local)
|
|||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_failed_barrier(int ee_flags)
|
|
||||||
{
|
|
||||||
return (ee_flags & (EE_IS_BARRIER|EE_WAS_ERROR|EE_RESUBMITTED))
|
|
||||||
== (EE_IS_BARRIER|EE_WAS_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* writes on behalf of the partner, or resync writes,
|
/* writes on behalf of the partner, or resync writes,
|
||||||
* "submitted" by the receiver, final stage. */
|
* "submitted" by the receiver, final stage. */
|
||||||
static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local)
|
static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local)
|
||||||
@ -119,21 +113,6 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
|
|||||||
int is_syncer_req;
|
int is_syncer_req;
|
||||||
int do_al_complete_io;
|
int do_al_complete_io;
|
||||||
|
|
||||||
/* if this is a failed barrier request, disable use of barriers,
|
|
||||||
* and schedule for resubmission */
|
|
||||||
if (is_failed_barrier(e->flags)) {
|
|
||||||
drbd_bump_write_ordering(mdev, WO_bdev_flush);
|
|
||||||
spin_lock_irqsave(&mdev->req_lock, flags);
|
|
||||||
list_del(&e->w.list);
|
|
||||||
e->flags = (e->flags & ~EE_WAS_ERROR) | EE_RESUBMITTED;
|
|
||||||
e->w.cb = w_e_reissue;
|
|
||||||
/* put_ldev actually happens below, once we come here again. */
|
|
||||||
__release(local);
|
|
||||||
spin_unlock_irqrestore(&mdev->req_lock, flags);
|
|
||||||
drbd_queue_work(&mdev->data.work, &e->w);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
D_ASSERT(e->block_id != ID_VACANT);
|
D_ASSERT(e->block_id != ID_VACANT);
|
||||||
|
|
||||||
/* after we moved e to done_ee,
|
/* after we moved e to done_ee,
|
||||||
@ -925,7 +904,7 @@ out:
|
|||||||
drbd_md_sync(mdev);
|
drbd_md_sync(mdev);
|
||||||
|
|
||||||
if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
|
if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
|
||||||
dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
|
dev_info(DEV, "Writing the whole bitmap\n");
|
||||||
drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
|
drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,12 +481,6 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
|
|||||||
if (bio_rw(bio) == WRITE) {
|
if (bio_rw(bio) == WRITE) {
|
||||||
struct file *file = lo->lo_backing_file;
|
struct file *file = lo->lo_backing_file;
|
||||||
|
|
||||||
/* REQ_HARDBARRIER is deprecated */
|
|
||||||
if (bio->bi_rw & REQ_HARDBARRIER) {
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bio->bi_rw & REQ_FLUSH) {
|
if (bio->bi_rw & REQ_FLUSH) {
|
||||||
ret = vfs_fsync(file, 0);
|
ret = vfs_fsync(file, 0);
|
||||||
if (unlikely(ret && ret != -EINVAL)) {
|
if (unlikely(ret && ret != -EINVAL)) {
|
||||||
|
@ -289,8 +289,6 @@ static int blkif_queue_request(struct request *req)
|
|||||||
|
|
||||||
ring_req->operation = rq_data_dir(req) ?
|
ring_req->operation = rq_data_dir(req) ?
|
||||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||||
if (req->cmd_flags & REQ_HARDBARRIER)
|
|
||||||
ring_req->operation = BLKIF_OP_WRITE_BARRIER;
|
|
||||||
|
|
||||||
ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
|
ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
|
||||||
BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
||||||
|
@ -706,7 +706,7 @@ static struct mdk_personality *find_pers(int level, char *clevel)
|
|||||||
/* return the offset of the super block in 512byte sectors */
|
/* return the offset of the super block in 512byte sectors */
|
||||||
static inline sector_t calc_dev_sboffset(struct block_device *bdev)
|
static inline sector_t calc_dev_sboffset(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
sector_t num_sectors = bdev->bd_inode->i_size / 512;
|
sector_t num_sectors = i_size_read(bdev->bd_inode) / 512;
|
||||||
return MD_NEW_SIZE_SECTORS(num_sectors);
|
return MD_NEW_SIZE_SECTORS(num_sectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1386,7 +1386,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
|
|||||||
*/
|
*/
|
||||||
switch(minor_version) {
|
switch(minor_version) {
|
||||||
case 0:
|
case 0:
|
||||||
sb_start = rdev->bdev->bd_inode->i_size >> 9;
|
sb_start = i_size_read(rdev->bdev->bd_inode) >> 9;
|
||||||
sb_start -= 8*2;
|
sb_start -= 8*2;
|
||||||
sb_start &= ~(sector_t)(4*2-1);
|
sb_start &= ~(sector_t)(4*2-1);
|
||||||
break;
|
break;
|
||||||
@ -1472,7 +1472,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
if (minor_version)
|
if (minor_version)
|
||||||
rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) -
|
rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
|
||||||
le64_to_cpu(sb->data_offset);
|
le64_to_cpu(sb->data_offset);
|
||||||
else
|
else
|
||||||
rdev->sectors = rdev->sb_start;
|
rdev->sectors = rdev->sb_start;
|
||||||
@ -1680,7 +1680,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
|
|||||||
return 0; /* component must fit device */
|
return 0; /* component must fit device */
|
||||||
if (rdev->sb_start < rdev->data_offset) {
|
if (rdev->sb_start < rdev->data_offset) {
|
||||||
/* minor versions 1 and 2; superblock before data */
|
/* minor versions 1 and 2; superblock before data */
|
||||||
max_sectors = rdev->bdev->bd_inode->i_size >> 9;
|
max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
|
||||||
max_sectors -= rdev->data_offset;
|
max_sectors -= rdev->data_offset;
|
||||||
if (!num_sectors || num_sectors > max_sectors)
|
if (!num_sectors || num_sectors > max_sectors)
|
||||||
num_sectors = max_sectors;
|
num_sectors = max_sectors;
|
||||||
@ -1690,7 +1690,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
|
|||||||
} else {
|
} else {
|
||||||
/* minor version 0; superblock after data */
|
/* minor version 0; superblock after data */
|
||||||
sector_t sb_start;
|
sector_t sb_start;
|
||||||
sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
|
sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
|
||||||
sb_start &= ~(sector_t)(4*2 - 1);
|
sb_start &= ~(sector_t)(4*2 - 1);
|
||||||
max_sectors = rdev->sectors + sb_start - rdev->sb_start;
|
max_sectors = rdev->sectors + sb_start - rdev->sb_start;
|
||||||
if (!num_sectors || num_sectors > max_sectors)
|
if (!num_sectors || num_sectors > max_sectors)
|
||||||
@ -2584,7 +2584,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
|
|||||||
if (!sectors)
|
if (!sectors)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
} else if (!sectors)
|
} else if (!sectors)
|
||||||
sectors = (rdev->bdev->bd_inode->i_size >> 9) -
|
sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
|
||||||
rdev->data_offset;
|
rdev->data_offset;
|
||||||
}
|
}
|
||||||
if (sectors < my_mddev->dev_sectors)
|
if (sectors < my_mddev->dev_sectors)
|
||||||
@ -2797,7 +2797,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
|
|||||||
|
|
||||||
kobject_init(&rdev->kobj, &rdev_ktype);
|
kobject_init(&rdev->kobj, &rdev_ktype);
|
||||||
|
|
||||||
size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
|
size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
|
||||||
if (!size) {
|
if (!size) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"md: %s has zero or unknown size, marking faulty!\n",
|
"md: %s has zero or unknown size, marking faulty!\n",
|
||||||
@ -5235,8 +5235,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
|
|||||||
|
|
||||||
if (!mddev->persistent) {
|
if (!mddev->persistent) {
|
||||||
printk(KERN_INFO "md: nonpersistent superblock ...\n");
|
printk(KERN_INFO "md: nonpersistent superblock ...\n");
|
||||||
rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
|
rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
|
||||||
} else
|
} else
|
||||||
rdev->sb_start = calc_dev_sboffset(rdev->bdev);
|
rdev->sb_start = calc_dev_sboffset(rdev->bdev);
|
||||||
rdev->sectors = rdev->sb_start;
|
rdev->sectors = rdev->sb_start;
|
||||||
|
|
||||||
@ -5306,7 +5306,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
|
|||||||
if (mddev->persistent)
|
if (mddev->persistent)
|
||||||
rdev->sb_start = calc_dev_sboffset(rdev->bdev);
|
rdev->sb_start = calc_dev_sboffset(rdev->bdev);
|
||||||
else
|
else
|
||||||
rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
|
rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
|
||||||
|
|
||||||
rdev->sectors = rdev->sb_start;
|
rdev->sectors = rdev->sb_start;
|
||||||
|
|
||||||
|
@ -320,19 +320,11 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
|
|||||||
"changed. The Linux SCSI layer does not "
|
"changed. The Linux SCSI layer does not "
|
||||||
"automatically adjust these parameters.\n");
|
"automatically adjust these parameters.\n");
|
||||||
|
|
||||||
if (scmd->request->cmd_flags & REQ_HARDBARRIER)
|
/*
|
||||||
/*
|
* Pass the UA upwards for a determination in the completion
|
||||||
* barrier requests should always retry on UA
|
* functions.
|
||||||
* otherwise block will get a spurious error
|
*/
|
||||||
*/
|
return SUCCESS;
|
||||||
return NEEDS_RETRY;
|
|
||||||
else
|
|
||||||
/*
|
|
||||||
* for normal (non barrier) commands, pass the
|
|
||||||
* UA upwards for a determination in the
|
|
||||||
* completion functions
|
|
||||||
*/
|
|
||||||
return SUCCESS;
|
|
||||||
|
|
||||||
/* these three are not supported */
|
/* these three are not supported */
|
||||||
case COPY_ABORTED:
|
case COPY_ABORTED:
|
||||||
|
@ -331,10 +331,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
|||||||
|
|
||||||
iu->iu_id = IU_ID_COMMAND;
|
iu->iu_id = IU_ID_COMMAND;
|
||||||
iu->tag = cpu_to_be16(stream_id);
|
iu->tag = cpu_to_be16(stream_id);
|
||||||
if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER))
|
iu->prio_attr = UAS_SIMPLE_TAG;
|
||||||
iu->prio_attr = UAS_ORDERED_TAG;
|
|
||||||
else
|
|
||||||
iu->prio_attr = UAS_SIMPLE_TAG;
|
|
||||||
iu->len = len;
|
iu->len = len;
|
||||||
int_to_scsilun(sdev->lun, &iu->lun);
|
int_to_scsilun(sdev->lun, &iu->lun);
|
||||||
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
|
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
|
||||||
|
23
fs/bio.c
23
fs/bio.c
@ -370,6 +370,9 @@ struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
|
|||||||
{
|
{
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
|
|
||||||
|
if (nr_iovecs > UIO_MAXIOV)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
|
bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
|
||||||
gfp_mask);
|
gfp_mask);
|
||||||
if (unlikely(!bio))
|
if (unlikely(!bio))
|
||||||
@ -697,8 +700,12 @@ static void bio_free_map_data(struct bio_map_data *bmd)
|
|||||||
static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
|
static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
|
||||||
gfp_t gfp_mask)
|
gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
struct bio_map_data *bmd = kmalloc(sizeof(*bmd), gfp_mask);
|
struct bio_map_data *bmd;
|
||||||
|
|
||||||
|
if (iov_count > UIO_MAXIOV)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bmd = kmalloc(sizeof(*bmd), gfp_mask);
|
||||||
if (!bmd)
|
if (!bmd)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -827,6 +834,12 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
|||||||
end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
start = uaddr >> PAGE_SHIFT;
|
start = uaddr >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overflow, abort
|
||||||
|
*/
|
||||||
|
if (end < start)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
nr_pages += end - start;
|
nr_pages += end - start;
|
||||||
len += iov[i].iov_len;
|
len += iov[i].iov_len;
|
||||||
}
|
}
|
||||||
@ -955,6 +968,12 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
|
|||||||
unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
unsigned long start = uaddr >> PAGE_SHIFT;
|
unsigned long start = uaddr >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overflow, abort
|
||||||
|
*/
|
||||||
|
if (end < start)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
nr_pages += end - start;
|
nr_pages += end - start;
|
||||||
/*
|
/*
|
||||||
* buffer must be aligned to at least hardsector size for now
|
* buffer must be aligned to at least hardsector size for now
|
||||||
@ -982,7 +1001,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
|
|||||||
unsigned long start = uaddr >> PAGE_SHIFT;
|
unsigned long start = uaddr >> PAGE_SHIFT;
|
||||||
const int local_nr_pages = end - start;
|
const int local_nr_pages = end - start;
|
||||||
const int page_limit = cur_page + local_nr_pages;
|
const int page_limit = cur_page + local_nr_pages;
|
||||||
|
|
||||||
ret = get_user_pages_fast(uaddr, local_nr_pages,
|
ret = get_user_pages_fast(uaddr, local_nr_pages,
|
||||||
write_to_vm, &pages[cur_page]);
|
write_to_vm, &pages[cur_page]);
|
||||||
if (ret < local_nr_pages) {
|
if (ret < local_nr_pages) {
|
||||||
|
18
fs/ioprio.c
18
fs/ioprio.c
@ -111,12 +111,14 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
|
|||||||
read_lock(&tasklist_lock);
|
read_lock(&tasklist_lock);
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case IOPRIO_WHO_PROCESS:
|
case IOPRIO_WHO_PROCESS:
|
||||||
|
rcu_read_lock();
|
||||||
if (!who)
|
if (!who)
|
||||||
p = current;
|
p = current;
|
||||||
else
|
else
|
||||||
p = find_task_by_vpid(who);
|
p = find_task_by_vpid(who);
|
||||||
if (p)
|
if (p)
|
||||||
ret = set_task_ioprio(p, ioprio);
|
ret = set_task_ioprio(p, ioprio);
|
||||||
|
rcu_read_unlock();
|
||||||
break;
|
break;
|
||||||
case IOPRIO_WHO_PGRP:
|
case IOPRIO_WHO_PGRP:
|
||||||
if (!who)
|
if (!who)
|
||||||
@ -139,7 +141,12 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
do_each_thread(g, p) {
|
do_each_thread(g, p) {
|
||||||
if (__task_cred(p)->uid != who)
|
int match;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
match = __task_cred(p)->uid == who;
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (!match)
|
||||||
continue;
|
continue;
|
||||||
ret = set_task_ioprio(p, ioprio);
|
ret = set_task_ioprio(p, ioprio);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -200,12 +207,14 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
|
|||||||
read_lock(&tasklist_lock);
|
read_lock(&tasklist_lock);
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case IOPRIO_WHO_PROCESS:
|
case IOPRIO_WHO_PROCESS:
|
||||||
|
rcu_read_lock();
|
||||||
if (!who)
|
if (!who)
|
||||||
p = current;
|
p = current;
|
||||||
else
|
else
|
||||||
p = find_task_by_vpid(who);
|
p = find_task_by_vpid(who);
|
||||||
if (p)
|
if (p)
|
||||||
ret = get_task_ioprio(p);
|
ret = get_task_ioprio(p);
|
||||||
|
rcu_read_unlock();
|
||||||
break;
|
break;
|
||||||
case IOPRIO_WHO_PGRP:
|
case IOPRIO_WHO_PGRP:
|
||||||
if (!who)
|
if (!who)
|
||||||
@ -232,7 +241,12 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
do_each_thread(g, p) {
|
do_each_thread(g, p) {
|
||||||
if (__task_cred(p)->uid != user->uid)
|
int match;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
match = __task_cred(p)->uid == user->uid;
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (!match)
|
||||||
continue;
|
continue;
|
||||||
tmpio = get_task_ioprio(p);
|
tmpio = get_task_ioprio(p);
|
||||||
if (tmpio < 0)
|
if (tmpio < 0)
|
||||||
|
@ -66,10 +66,6 @@
|
|||||||
#define bio_offset(bio) bio_iovec((bio))->bv_offset
|
#define bio_offset(bio) bio_iovec((bio))->bv_offset
|
||||||
#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_idx)
|
#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_idx)
|
||||||
#define bio_sectors(bio) ((bio)->bi_size >> 9)
|
#define bio_sectors(bio) ((bio)->bi_size >> 9)
|
||||||
#define bio_empty_barrier(bio) \
|
|
||||||
((bio->bi_rw & REQ_HARDBARRIER) && \
|
|
||||||
!bio_has_data(bio) && \
|
|
||||||
!(bio->bi_rw & REQ_DISCARD))
|
|
||||||
|
|
||||||
static inline unsigned int bio_cur_bytes(struct bio *bio)
|
static inline unsigned int bio_cur_bytes(struct bio *bio)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,6 @@ enum rq_flag_bits {
|
|||||||
__REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */
|
__REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */
|
||||||
__REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */
|
__REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */
|
||||||
|
|
||||||
__REQ_HARDBARRIER, /* may not be passed by drive either */
|
|
||||||
__REQ_SYNC, /* request is sync (sync write or read) */
|
__REQ_SYNC, /* request is sync (sync write or read) */
|
||||||
__REQ_META, /* metadata io request */
|
__REQ_META, /* metadata io request */
|
||||||
__REQ_DISCARD, /* request to discard sectors */
|
__REQ_DISCARD, /* request to discard sectors */
|
||||||
@ -159,7 +158,6 @@ enum rq_flag_bits {
|
|||||||
#define REQ_FAILFAST_DEV (1 << __REQ_FAILFAST_DEV)
|
#define REQ_FAILFAST_DEV (1 << __REQ_FAILFAST_DEV)
|
||||||
#define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT)
|
#define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT)
|
||||||
#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER)
|
#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER)
|
||||||
#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER)
|
|
||||||
#define REQ_SYNC (1 << __REQ_SYNC)
|
#define REQ_SYNC (1 << __REQ_SYNC)
|
||||||
#define REQ_META (1 << __REQ_META)
|
#define REQ_META (1 << __REQ_META)
|
||||||
#define REQ_DISCARD (1 << __REQ_DISCARD)
|
#define REQ_DISCARD (1 << __REQ_DISCARD)
|
||||||
@ -168,8 +166,8 @@ enum rq_flag_bits {
|
|||||||
#define REQ_FAILFAST_MASK \
|
#define REQ_FAILFAST_MASK \
|
||||||
(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
|
(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
|
||||||
#define REQ_COMMON_MASK \
|
#define REQ_COMMON_MASK \
|
||||||
(REQ_WRITE | REQ_FAILFAST_MASK | REQ_HARDBARRIER | REQ_SYNC | \
|
(REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \
|
||||||
REQ_META | REQ_DISCARD | REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
|
REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
|
||||||
#define REQ_CLONE_MASK REQ_COMMON_MASK
|
#define REQ_CLONE_MASK REQ_COMMON_MASK
|
||||||
|
|
||||||
#define REQ_UNPLUG (1 << __REQ_UNPLUG)
|
#define REQ_UNPLUG (1 << __REQ_UNPLUG)
|
||||||
|
@ -552,8 +552,7 @@ static inline void blk_clear_queue_full(struct request_queue *q, int sync)
|
|||||||
* it already be started by driver.
|
* it already be started by driver.
|
||||||
*/
|
*/
|
||||||
#define RQ_NOMERGE_FLAGS \
|
#define RQ_NOMERGE_FLAGS \
|
||||||
(REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER | \
|
(REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA)
|
||||||
REQ_FLUSH | REQ_FUA)
|
|
||||||
#define rq_mergeable(rq) \
|
#define rq_mergeable(rq) \
|
||||||
(!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
|
(!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
|
||||||
(((rq)->cmd_flags & REQ_DISCARD) || \
|
(((rq)->cmd_flags & REQ_DISCARD) || \
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
|
|
||||||
extern const char *drbd_buildtag(void);
|
extern const char *drbd_buildtag(void);
|
||||||
#define REL_VERSION "8.3.9rc2"
|
#define REL_VERSION "8.3.9"
|
||||||
#define API_VERSION 88
|
#define API_VERSION 88
|
||||||
#define PRO_VERSION_MIN 86
|
#define PRO_VERSION_MIN 86
|
||||||
#define PRO_VERSION_MAX 95
|
#define PRO_VERSION_MAX 95
|
||||||
|
@ -76,7 +76,6 @@ int put_io_context(struct io_context *ioc);
|
|||||||
void exit_io_context(struct task_struct *task);
|
void exit_io_context(struct task_struct *task);
|
||||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
|
||||||
#else
|
#else
|
||||||
static inline void exit_io_context(struct task_struct *task)
|
static inline void exit_io_context(struct task_struct *task)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,6 @@ static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector,
|
|||||||
static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
|
static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
|
||||||
BLK_TC_ACT(BLK_TC_WRITE) };
|
BLK_TC_ACT(BLK_TC_WRITE) };
|
||||||
|
|
||||||
#define BLK_TC_HARDBARRIER BLK_TC_BARRIER
|
|
||||||
#define BLK_TC_RAHEAD BLK_TC_AHEAD
|
#define BLK_TC_RAHEAD BLK_TC_AHEAD
|
||||||
|
|
||||||
/* The ilog2() calls fall out because they're constant */
|
/* The ilog2() calls fall out because they're constant */
|
||||||
@ -196,7 +195,6 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
what |= ddir_act[rw & WRITE];
|
what |= ddir_act[rw & WRITE];
|
||||||
what |= MASK_TC_BIT(rw, HARDBARRIER);
|
|
||||||
what |= MASK_TC_BIT(rw, SYNC);
|
what |= MASK_TC_BIT(rw, SYNC);
|
||||||
what |= MASK_TC_BIT(rw, RAHEAD);
|
what |= MASK_TC_BIT(rw, RAHEAD);
|
||||||
what |= MASK_TC_BIT(rw, META);
|
what |= MASK_TC_BIT(rw, META);
|
||||||
@ -1807,8 +1805,6 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
|
|||||||
|
|
||||||
if (rw & REQ_RAHEAD)
|
if (rw & REQ_RAHEAD)
|
||||||
rwbs[i++] = 'A';
|
rwbs[i++] = 'A';
|
||||||
if (rw & REQ_HARDBARRIER)
|
|
||||||
rwbs[i++] = 'B';
|
|
||||||
if (rw & REQ_SYNC)
|
if (rw & REQ_SYNC)
|
||||||
rwbs[i++] = 'S';
|
rwbs[i++] = 'S';
|
||||||
if (rw & REQ_META)
|
if (rw & REQ_META)
|
||||||
|
Loading…
Reference in New Issue
Block a user