cs5535: add a generic MFGPT driver
[safe/jmp/linux-2.6] / drivers / block / loop.c
index 2621ed2..bd112c8 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/loop.h>
@@ -476,7 +475,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
        pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
 
        if (bio_rw(bio) == WRITE) {
-               int barrier = bio_barrier(bio);
+               bool barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
                struct file *file = lo->lo_backing_file;
 
                if (barrier) {
@@ -511,11 +510,7 @@ out:
  */
 static void loop_add_bio(struct loop_device *lo, struct bio *bio)
 {
-       if (lo->lo_biotail) {
-               lo->lo_biotail->bi_next = bio;
-               lo->lo_biotail = bio;
-       } else
-               lo->lo_bio = lo->lo_biotail = bio;
+       bio_list_add(&lo->lo_bio_list, bio);
 }
 
 /*
@@ -523,16 +518,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio)
  */
 static struct bio *loop_get_bio(struct loop_device *lo)
 {
-       struct bio *bio;
-
-       if ((bio = lo->lo_bio)) {
-               if (bio == lo->lo_biotail)
-                       lo->lo_biotail = NULL;
-               lo->lo_bio = bio->bi_next;
-               bio->bi_next = NULL;
-       }
-
-       return bio;
+       return bio_list_pop(&lo->lo_bio_list);
 }
 
 static int loop_make_request(struct request_queue *q, struct bio *old_bio)
@@ -609,12 +595,13 @@ static int loop_thread(void *data)
 
        set_user_nice(current, -20);
 
-       while (!kthread_should_stop() || lo->lo_bio) {
+       while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) {
 
                wait_event_interruptible(lo->lo_event,
-                               lo->lo_bio || kthread_should_stop());
+                               !bio_list_empty(&lo->lo_bio_list) ||
+                               kthread_should_stop());
 
-               if (!lo->lo_bio)
+               if (bio_list_empty(&lo->lo_bio_list))
                        continue;
                spin_lock_irq(&lo->lo_lock);
                bio = loop_get_bio(lo);
@@ -721,10 +708,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
        if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
                goto out_putf;
 
-       /* new backing store needs to support loop (eg splice_read) */
-       if (!inode->i_fop->splice_read)
-               goto out_putf;
-
        /* size of the new backing store needs to be the same */
        if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
                goto out_putf;
@@ -800,12 +783,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
        error = -EINVAL;
        if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                const struct address_space_operations *aops = mapping->a_ops;
-               /*
-                * If we can't read - sorry. If we only can't write - well,
-                * it's going to be read-only.
-                */
-               if (!file->f_op->splice_read)
-                       goto out_putf;
+
                if (aops->write_begin)
                        lo_flags |= LO_FLAGS_USE_AOPS;
                if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
@@ -841,7 +819,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
        lo->old_gfp_mask = mapping_gfp_mask(mapping);
        mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
 
-       lo->lo_bio = lo->lo_biotail = NULL;
+       bio_list_init(&lo->lo_bio_list);
 
        /*
         * set queue make_request_fn, and add limits based on lower level
@@ -971,7 +949,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
        lo->lo_state = Lo_unbound;
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
-       if (max_part > 0)
+       if (max_part > 0 && bdev)
                ioctl_by_bdev(bdev, BLKRRPART, 0);
        mutex_unlock(&lo->lo_ctl_mutex);
        /*
@@ -1192,6 +1170,30 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
        return err;
 }
 
+static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
+{
+       int err;
+       sector_t sec;
+       loff_t sz;
+
+       err = -ENXIO;
+       if (unlikely(lo->lo_state != Lo_bound))
+               goto out;
+       err = figure_loop_size(lo);
+       if (unlikely(err))
+               goto out;
+       sec = get_capacity(lo->lo_disk);
+       /* the width of sector_t may be narrow for bit-shift */
+       sz = sec;
+       sz <<= 9;
+       mutex_lock(&bdev->bd_mutex);
+       bd_set_size(bdev, sz);
+       mutex_unlock(&bdev->bd_mutex);
+
+ out:
+       return err;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        unsigned int cmd, unsigned long arg)
 {
@@ -1224,6 +1226,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        case LOOP_GET_STATUS64:
                err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
                break;
+       case LOOP_SET_CAPACITY:
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_capacity(lo, bdev);
+               break;
        default:
                err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
@@ -1371,6 +1378,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
                        lo, (struct compat_loop_info __user *) arg);
                mutex_unlock(&lo->lo_ctl_mutex);
                break;
+       case LOOP_SET_CAPACITY:
        case LOOP_CLR_FD:
        case LOOP_GET_STATUS64:
        case LOOP_SET_STATUS64:
@@ -1401,6 +1409,7 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
 static int lo_release(struct gendisk *disk, fmode_t mode)
 {
        struct loop_device *lo = disk->private_data;
+       int err;
 
        mutex_lock(&lo->lo_ctl_mutex);
 
@@ -1412,7 +1421,9 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
                 * In autoclear mode, stop the loop thread
                 * and remove configuration after last close.
                 */
-               loop_clr_fd(lo, NULL);
+               err = loop_clr_fd(lo, NULL);
+               if (!err)
+                       goto out_unlocked;
        } else {
                /*
                 * Otherwise keep thread (if running) and config,
@@ -1423,11 +1434,11 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
 
 out:
        mutex_unlock(&lo->lo_ctl_mutex);
-
+out_unlocked:
        return 0;
 }
 
-static struct block_device_operations lo_fops = {
+static const struct block_device_operations lo_fops = {
        .owner =        THIS_MODULE,
        .open =         lo_open,
        .release =      lo_release,