diff options
| -rw-r--r-- | fs/block_dev.c | 72 | ||||
| -rw-r--r-- | fs/pipe.c | 20 |
2 files changed, 62 insertions, 30 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 7346c96308a5..99d6af811747 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -706,8 +706,13 @@ retry: | |||
| 706 | * @bdev is about to be opened exclusively. Check @bdev can be opened | 706 | * @bdev is about to be opened exclusively. Check @bdev can be opened |
| 707 | * exclusively and mark that an exclusive open is in progress. Each | 707 | * exclusively and mark that an exclusive open is in progress. Each |
| 708 | * successful call to this function must be matched with a call to | 708 | * successful call to this function must be matched with a call to |
| 709 | * either bd_claim() or bd_abort_claiming(). If this function | 709 | * either bd_finish_claiming() or bd_abort_claiming() (which do not |
| 710 | * succeeds, the matching bd_claim() is guaranteed to succeed. | 710 | * fail). |
| 711 | * | ||
| 712 | * This function is used to gain exclusive access to the block device | ||
| 713 | * without actually causing other exclusive open attempts to fail. It | ||
| 714 | * should be used when the open sequence itself requires exclusive | ||
| 715 | * access but may subsequently fail. | ||
| 711 | * | 716 | * |
| 712 | * CONTEXT: | 717 | * CONTEXT: |
| 713 | * Might sleep. | 718 | * Might sleep. |
| @@ -734,6 +739,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, | |||
| 734 | return ERR_PTR(-ENXIO); | 739 | return ERR_PTR(-ENXIO); |
| 735 | 740 | ||
| 736 | whole = bdget_disk(disk, 0); | 741 | whole = bdget_disk(disk, 0); |
| 742 | module_put(disk->fops->owner); | ||
| 737 | put_disk(disk); | 743 | put_disk(disk); |
| 738 | if (!whole) | 744 | if (!whole) |
| 739 | return ERR_PTR(-ENOMEM); | 745 | return ERR_PTR(-ENOMEM); |
| @@ -782,15 +788,46 @@ static void bd_abort_claiming(struct block_device *whole, void *holder) | |||
| 782 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | 788 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ |
| 783 | } | 789 | } |
| 784 | 790 | ||
| 791 | /* increment holders when we have a legitimate claim. requires bdev_lock */ | ||
| 792 | static void __bd_claim(struct block_device *bdev, struct block_device *whole, | ||
| 793 | void *holder) | ||
| 794 | { | ||
| 795 | /* note that for a whole device bd_holders | ||
| 796 | * will be incremented twice, and bd_holder will | ||
| 797 | * be set to bd_claim before being set to holder | ||
| 798 | */ | ||
| 799 | whole->bd_holders++; | ||
| 800 | whole->bd_holder = bd_claim; | ||
| 801 | bdev->bd_holders++; | ||
| 802 | bdev->bd_holder = holder; | ||
| 803 | } | ||
| 804 | |||
| 805 | /** | ||
| 806 | * bd_finish_claiming - finish claiming a block device | ||
| 807 | * @bdev: block device of interest (passed to bd_start_claiming()) | ||
| 808 | * @whole: whole block device returned by bd_start_claiming() | ||
| 809 | * @holder: holder trying to claim @bdev | ||
| 810 | * | ||
| 811 | * Finish a claiming block started by bd_start_claiming(). | ||
| 812 | * | ||
| 813 | * CONTEXT: | ||
| 814 | * Grabs and releases bdev_lock. | ||
| 815 | */ | ||
| 816 | static void bd_finish_claiming(struct block_device *bdev, | ||
| 817 | struct block_device *whole, void *holder) | ||
| 818 | { | ||
| 819 | spin_lock(&bdev_lock); | ||
| 820 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | ||
| 821 | __bd_claim(bdev, whole, holder); | ||
| 822 | __bd_abort_claiming(whole, holder); /* not actually an abort */ | ||
| 823 | } | ||
| 824 | |||
| 785 | /** | 825 | /** |
| 786 | * bd_claim - claim a block device | 826 | * bd_claim - claim a block device |
| 787 | * @bdev: block device to claim | 827 | * @bdev: block device to claim |
| 788 | * @holder: holder trying to claim @bdev | 828 | * @holder: holder trying to claim @bdev |
| 789 | * | 829 | * |
| 790 | * Try to claim @bdev which must have been opened successfully. This | 830 | * Try to claim @bdev which must have been opened successfully. |
| 791 | * function may be called with or without preceding | ||
| 792 | * blk_start_claiming(). In the former case, this function is always | ||
| 793 | * successful and terminates the claiming block. | ||
| 794 | * | 831 | * |
| 795 | * CONTEXT: | 832 | * CONTEXT: |
| 796 | * Might sleep. | 833 | * Might sleep. |
| @@ -806,23 +843,10 @@ int bd_claim(struct block_device *bdev, void *holder) | |||
| 806 | might_sleep(); | 843 | might_sleep(); |
| 807 | 844 | ||
| 808 | spin_lock(&bdev_lock); | 845 | spin_lock(&bdev_lock); |
| 809 | |||
| 810 | res = bd_prepare_to_claim(bdev, whole, holder); | 846 | res = bd_prepare_to_claim(bdev, whole, holder); |
| 811 | if (res == 0) { | 847 | if (res == 0) |
| 812 | /* note that for a whole device bd_holders | 848 | __bd_claim(bdev, whole, holder); |
| 813 | * will be incremented twice, and bd_holder will | 849 | spin_unlock(&bdev_lock); |
| 814 | * be set to bd_claim before being set to holder | ||
| 815 | */ | ||
| 816 | whole->bd_holders++; | ||
| 817 | whole->bd_holder = bd_claim; | ||
| 818 | bdev->bd_holders++; | ||
| 819 | bdev->bd_holder = holder; | ||
| 820 | } | ||
| 821 | |||
| 822 | if (whole->bd_claiming) | ||
| 823 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | ||
| 824 | else | ||
| 825 | spin_unlock(&bdev_lock); | ||
| 826 | 850 | ||
| 827 | return res; | 851 | return res; |
| 828 | } | 852 | } |
| @@ -1476,7 +1500,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
| 1476 | 1500 | ||
| 1477 | if (whole) { | 1501 | if (whole) { |
| 1478 | if (res == 0) | 1502 | if (res == 0) |
| 1479 | BUG_ON(bd_claim(bdev, filp) != 0); | 1503 | bd_finish_claiming(bdev, whole, filp); |
| 1480 | else | 1504 | else |
| 1481 | bd_abort_claiming(whole, filp); | 1505 | bd_abort_claiming(whole, filp); |
| 1482 | } | 1506 | } |
| @@ -1712,7 +1736,7 @@ struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *h | |||
| 1712 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) | 1736 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) |
| 1713 | goto out_blkdev_put; | 1737 | goto out_blkdev_put; |
| 1714 | 1738 | ||
| 1715 | BUG_ON(bd_claim(bdev, holder) != 0); | 1739 | bd_finish_claiming(bdev, whole, holder); |
| 1716 | return bdev; | 1740 | return bdev; |
| 1717 | 1741 | ||
| 1718 | out_blkdev_put: | 1742 | out_blkdev_put: |
| @@ -1145,13 +1145,20 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) | |||
| 1145 | * and adjust the indexes. | 1145 | * and adjust the indexes. |
| 1146 | */ | 1146 | */ |
| 1147 | if (pipe->nrbufs) { | 1147 | if (pipe->nrbufs) { |
| 1148 | const unsigned int tail = pipe->nrbufs & (pipe->buffers - 1); | 1148 | unsigned int tail; |
| 1149 | const unsigned int head = pipe->nrbufs - tail; | 1149 | unsigned int head; |
| 1150 | 1150 | ||
| 1151 | tail = pipe->curbuf + pipe->nrbufs; | ||
| 1152 | if (tail < pipe->buffers) | ||
| 1153 | tail = 0; | ||
| 1154 | else | ||
| 1155 | tail &= (pipe->buffers - 1); | ||
| 1156 | |||
| 1157 | head = pipe->nrbufs - tail; | ||
| 1151 | if (head) | 1158 | if (head) |
| 1152 | memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); | 1159 | memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); |
| 1153 | if (tail) | 1160 | if (tail) |
| 1154 | memcpy(bufs + head, pipe->bufs + pipe->curbuf, tail * sizeof(struct pipe_buffer)); | 1161 | memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); |
| 1155 | } | 1162 | } |
| 1156 | 1163 | ||
| 1157 | pipe->curbuf = 0; | 1164 | pipe->curbuf = 0; |
| @@ -1208,12 +1215,13 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 1208 | size = round_pipe_size(arg); | 1215 | size = round_pipe_size(arg); |
| 1209 | nr_pages = size >> PAGE_SHIFT; | 1216 | nr_pages = size >> PAGE_SHIFT; |
| 1210 | 1217 | ||
| 1218 | ret = -EINVAL; | ||
| 1219 | if (!nr_pages) | ||
| 1220 | goto out; | ||
| 1221 | |||
| 1211 | if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { | 1222 | if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { |
| 1212 | ret = -EPERM; | 1223 | ret = -EPERM; |
| 1213 | goto out; | 1224 | goto out; |
| 1214 | } else if (nr_pages < PAGE_SIZE) { | ||
| 1215 | ret = -EINVAL; | ||
| 1216 | goto out; | ||
| 1217 | } | 1225 | } |
| 1218 | ret = pipe_set_size(pipe, nr_pages); | 1226 | ret = pipe_set_size(pipe, nr_pages); |
| 1219 | break; | 1227 | break; |
