Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg/writeback
[pandora-kernel.git] / fs / block_dev.c
index 3c9a03e..f55aad4 100644 (file)
@@ -359,25 +359,30 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
        mutex_lock(&bd_inode->i_mutex);
        size = i_size_read(bd_inode);
 
+       retval = -EINVAL;
        switch (origin) {
-               case 2:
+               case SEEK_END:
                        offset += size;
                        break;
-               case 1:
+               case SEEK_CUR:
                        offset += file->f_pos;
+               case SEEK_SET:
+                       break;
+               default:
+                       goto out;
        }
-       retval = -EINVAL;
        if (offset >= 0 && offset <= size) {
                if (offset != file->f_pos) {
                        file->f_pos = offset;
                }
                retval = offset;
        }
+out:
        mutex_unlock(&bd_inode->i_mutex);
        return retval;
 }
        
-int blkdev_fsync(struct file *filp, int datasync)
+int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *bd_inode = filp->f_mapping->host;
        struct block_device *bdev = I_BDEV(bd_inode);
@@ -388,14 +393,10 @@ int blkdev_fsync(struct file *filp, int datasync)
         * i_mutex and doing so causes performance issues with concurrent
         * O_SYNC writers to a block device.
         */
-       mutex_unlock(&bd_inode->i_mutex);
-
        error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL);
        if (error == -EOPNOTSUPP)
                error = 0;
 
-       mutex_lock(&bd_inode->i_mutex);
-
        return error;
 }
 EXPORT_SYMBOL(blkdev_fsync);
@@ -766,7 +767,19 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
        if (!disk)
                return ERR_PTR(-ENXIO);
 
-       whole = bdget_disk(disk, 0);
+       /*
+        * Normally, @bdev should equal what's returned from bdget_disk()
+        * if partno is 0; however, some drivers (floppy) use multiple
+        * bdev's for the same physical device and @bdev may be one of the
+        * aliases.  Keep @bdev if partno is 0.  This means claimer
+        * tracking is broken for those devices but it has always been that
+        * way.
+        */
+       if (partno)
+               whole = bdget_disk(disk, 0);
+       else
+               whole = bdgrab(bdev);
+
        module_put(disk->fops->owner);
        put_disk(disk);
        if (!whole)
@@ -1439,6 +1452,8 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
 
 int blkdev_put(struct block_device *bdev, fmode_t mode)
 {
+       mutex_lock(&bdev->bd_mutex);
+
        if (mode & FMODE_EXCL) {
                bool bdev_free;
 
@@ -1447,7 +1462,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
                 * are protected with bdev_lock.  bd_mutex is to
                 * synchronize disk_holder unlinking.
                 */
-               mutex_lock(&bdev->bd_mutex);
                spin_lock(&bdev_lock);
 
                WARN_ON_ONCE(--bdev->bd_holders < 0);
@@ -1465,17 +1479,21 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
                 * If this was the last claim, remove holder link and
                 * unblock evpoll if it was a write holder.
                 */
-               if (bdev_free) {
-                       if (bdev->bd_write_holder) {
-                               disk_unblock_events(bdev->bd_disk);
-                               disk_check_events(bdev->bd_disk);
-                               bdev->bd_write_holder = false;
-                       }
+               if (bdev_free && bdev->bd_write_holder) {
+                       disk_unblock_events(bdev->bd_disk);
+                       bdev->bd_write_holder = false;
                }
-
-               mutex_unlock(&bdev->bd_mutex);
        }
 
+       /*
+        * Trigger event checking and tell drivers to flush MEDIA_CHANGE
+        * event.  This is to ensure detection of media removal commanded
+        * from userland - e.g. eject(1).
+        */
+       disk_flush_events(bdev->bd_disk, DISK_EVENT_MEDIA_CHANGE);
+
+       mutex_unlock(&bdev->bd_mutex);
+
        return __blkdev_put(bdev, mode, 0);
 }
 EXPORT_SYMBOL(blkdev_put);