block: kill GENHD_FL_FAIL and use part0->make_it_fail
[safe/jmp/linux-2.6] / include / linux / genhd.h
index 9756fc1..3d15b42 100644 (file)
  */
 
 #include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/rcupdate.h>
 
 #ifdef CONFIG_BLOCK
 
+#define kobj_to_dev(k)         container_of((k), struct device, kobj)
+#define dev_to_disk(device)    container_of((device), struct gendisk, part0.__dev)
+#define dev_to_part(device)    container_of((device), struct hd_struct, __dev)
+#define disk_to_dev(disk)      (&(disk)->part0.__dev)
+#define part_to_dev(part)      (&((part)->__dev))
+
+extern struct device_type part_type;
+extern struct kobject *block_depr;
+extern struct class block_class;
+
+extern const struct seq_operations partitions_op;
+extern const struct seq_operations diskstats_op;
+
 enum {
 /* These three have identical behaviour; use the second one if DOS FDISK gets
    confused about extended/logical partitions starting past cylinder 1023. */
@@ -43,24 +58,6 @@ enum {
        UNIXWARE_PARTITION = 0x63,      /* Same as GNU_HURD and SCO Unix */
 };
 
-#ifndef __KERNEL__
-
-struct partition {
-       unsigned char boot_ind;         /* 0x80 - active */
-       unsigned char head;             /* starting head */
-       unsigned char sector;           /* starting sector */
-       unsigned char cyl;              /* starting cylinder */
-       unsigned char sys_ind;          /* What partition type */
-       unsigned char end_head;         /* end head */
-       unsigned char end_sector;       /* end sector */
-       unsigned char end_cyl;          /* end cylinder */
-       unsigned int start_sect;        /* starting sector counting from 0 */
-       unsigned int nr_sects;          /* nr of sectors in partition */
-} __attribute__((packed));
-
-#endif
-
-#ifdef __KERNEL__
 #include <linux/major.h>
 #include <linux/device.h>
 #include <linux/smp.h>
@@ -81,16 +78,32 @@ struct partition {
        __le32 nr_sects;                /* nr of sectors in partition */
 } __attribute__((packed));
 
+struct disk_stats {
+       unsigned long sectors[2];       /* READs and WRITEs */
+       unsigned long ios[2];
+       unsigned long merges[2];
+       unsigned long ticks[2];
+       unsigned long io_ticks;
+       unsigned long time_in_queue;
+};
+       
 struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
-       struct kobject kobj;
+       struct device __dev;
        struct kobject *holder_dir;
-       unsigned ios[2], sectors[2];    /* READs and WRITEs */
        int policy, partno;
 #ifdef CONFIG_FAIL_MAKE_REQUEST
        int make_it_fail;
 #endif
+       unsigned long stamp;
+       int in_flight;
+#ifdef CONFIG_SMP
+       struct disk_stats *dkstats;
+#else
+       struct disk_stats dkstats;
+#endif
+       struct rcu_head rcu_head;
 };
 
 #define GENHD_FL_REMOVABLE                     1
@@ -99,38 +112,37 @@ struct hd_struct {
 #define GENHD_FL_CD                            8
 #define GENHD_FL_UP                            16
 #define GENHD_FL_SUPPRESS_PARTITION_INFO       32
-#define GENHD_FL_FAIL                          64
 
-struct disk_stats {
-       unsigned long sectors[2];       /* READs and WRITEs */
-       unsigned long ios[2];
-       unsigned long merges[2];
-       unsigned long ticks[2];
-       unsigned long io_ticks;
-       unsigned long time_in_queue;
-};
-       
 struct gendisk {
+       /* major, first_minor, minors and ext_minors are input
+        * parameters only, don't use directly.  Use disk_devt() and
+        * disk_max_parts().
+        */
        int major;                      /* major number of driver */
        int first_minor;
        int minors;                     /* maximum number of minors, =1 for
                                          * disks that can't be partitioned. */
+       int ext_minors;                 /* number of extended dynamic minors */
+
        char disk_name[32];             /* name of major driver */
-       struct hd_struct **part;        /* [indexed by minor] */
-       int part_uevent_suppress;
+
+       /* Array of pointers to partitions indexed by partno.
+        * Protected with matching bdev lock but stat and other
+        * non-critical accesses use RCU.  Always access through
+        * helpers.
+        */
+       struct hd_struct **__part;
+       struct hd_struct part0;
+
        struct block_device_operations *fops;
        struct request_queue *queue;
        void *private_data;
-       sector_t capacity;
 
        int flags;
-       struct device *driverfs_dev;
-       struct kobject kobj;
-       struct kobject *holder_dir;
+       struct device *driverfs_dev;  // FIXME: remove
        struct kobject *slave_dir;
 
        struct timer_rand_state *random;
-       int policy;
 
        atomic_t sync_io;               /* RAID */
        unsigned long stamp;
@@ -141,24 +153,90 @@ struct gendisk {
        struct disk_stats dkstats;
 #endif
        struct work_struct async_notify;
+#ifdef  CONFIG_BLK_DEV_INTEGRITY
+       struct blk_integrity *integrity;
+#endif
 };
 
-/* Structure for sysfs attributes on block devices */
-struct disk_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct gendisk *, char *);
-       ssize_t (*store)(struct gendisk *, const char *, size_t);
+static inline struct gendisk *part_to_disk(struct hd_struct *part)
+{
+       if (likely(part)) {
+               if (part->partno)
+                       return dev_to_disk(part_to_dev(part)->parent);
+               else
+                       return dev_to_disk(part_to_dev(part));
+       }
+       return NULL;
+}
+
+static inline int disk_max_parts(struct gendisk *disk)
+{
+       return disk->minors + disk->ext_minors;
+}
+
+static inline bool disk_partitionable(struct gendisk *disk)
+{
+       return disk_max_parts(disk) > 1;
+}
+
+static inline dev_t disk_devt(struct gendisk *disk)
+{
+       return disk_to_dev(disk)->devt;
+}
+
+static inline dev_t part_devt(struct hd_struct *part)
+{
+       return part_to_dev(part)->devt;
+}
+
+extern struct hd_struct *disk_get_part(struct gendisk *disk, int partno);
+
+static inline void disk_put_part(struct hd_struct *part)
+{
+       if (likely(part))
+               put_device(part_to_dev(part));
+}
+
+/*
+ * Smarter partition iterator without context limits.
+ */
+#define DISK_PITER_REVERSE     (1 << 0) /* iterate in the reverse direction */
+#define DISK_PITER_INCL_EMPTY  (1 << 1) /* include 0-sized parts */
+#define DISK_PITER_INCL_PART0  (1 << 2) /* include partition 0 */
+
+struct disk_part_iter {
+       struct gendisk          *disk;
+       struct hd_struct        *part;
+       int                     idx;
+       unsigned int            flags;
 };
 
-/* 
+extern void disk_part_iter_init(struct disk_part_iter *piter,
+                                struct gendisk *disk, unsigned int flags);
+extern struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter);
+extern void disk_part_iter_exit(struct disk_part_iter *piter);
+
+extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
+                                            sector_t sector);
+
+/*
  * Macros to operate on percpu disk statistics:
  *
- * The __ variants should only be called in critical sections. The full
- * variants disable/enable preemption.
+ * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
+ * and should be called between disk_stat_lock() and
+ * disk_stat_unlock().
+ *
+ * part_stat_read() can be called at any time.
+ *
+ * part_stat_{add|set_all}() and {init|free}_part_stats are for
+ * internal use only.
  */
 #ifdef CONFIG_SMP
-#define __disk_stat_add(gendiskp, field, addnd)        \
-       (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
+#define disk_stat_lock()       ({ rcu_read_lock(); get_cpu(); })
+#define disk_stat_unlock()     do { put_cpu(); rcu_read_unlock(); } while (0)
+
+#define disk_stat_add(cpu, gendiskp, field, addnd)                     \
+       (per_cpu_ptr(gendiskp->dkstats, cpu)->field += addnd)
 
 #define disk_stat_read(gendiskp, field)                                        \
 ({                                                                     \
@@ -169,41 +247,95 @@ struct disk_attribute {
        res;                                                            \
 })
 
-static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)      {
+static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
+{
        int i;
+
        for_each_possible_cpu(i)
                memset(per_cpu_ptr(gendiskp->dkstats, i), value,
-                               sizeof (struct disk_stats));
+                               sizeof(struct disk_stats));
 }              
-                               
-#else
-#define __disk_stat_add(gendiskp, field, addnd) \
-                               (gendiskp->dkstats.field += addnd)
+
+#define part_stat_add(cpu, part, field, addnd)                         \
+       (per_cpu_ptr(part->dkstats, cpu)->field += addnd)
+
+#define all_stat_add(cpu, gendiskp, part, field, addnd, sector)                \
+({                                                                     \
+       if (part)                                                       \
+               part_stat_add(cpu, part, field, addnd);                 \
+       disk_stat_add(cpu, gendiskp, field, addnd);                     \
+})
+
+#define part_stat_read(part, field)                                    \
+({                                                                     \
+       typeof(part->dkstats->field) res = 0;                           \
+       int i;                                                          \
+       for_each_possible_cpu(i)                                        \
+               res += per_cpu_ptr(part->dkstats, i)->field;            \
+       res;                                                            \
+})
+
+static inline void part_stat_set_all(struct hd_struct *part, int value)
+{
+       int i;
+
+       for_each_possible_cpu(i)
+               memset(per_cpu_ptr(part->dkstats, i), value,
+                               sizeof(struct disk_stats));
+}
+
+#else /* !CONFIG_SMP */
+#define disk_stat_lock()       ({ rcu_read_lock(); 0; })
+#define disk_stat_unlock()     rcu_read_unlock()
+
+#define disk_stat_add(cpu, gendiskp, field, addnd)                     \
+       (gendiskp->dkstats.field += addnd)
 #define disk_stat_read(gendiskp, field)        (gendiskp->dkstats.field)
 
-static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)      {
+static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
+{
        memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
 }
-#endif
 
-#define disk_stat_add(gendiskp, field, addnd)                  \
-       do {                                                    \
-               preempt_disable();                              \
-               __disk_stat_add(gendiskp, field, addnd);        \
-               preempt_enable();                               \
-       } while (0)
+#define part_stat_add(cpu, part, field, addnd)                         \
+       (part->dkstats.field += addnd)
 
-#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1)
-#define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1)
+#define all_stat_add(cpu, gendiskp, part, field, addnd, sector)                \
+({                                                                     \
+       if (part)                                                       \
+               part_stat_add(cpu, part, field, addnd);                 \
+       disk_stat_add(cpu, gendiskp, field, addnd);                     \
+})
 
-#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1)
-#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
+#define part_stat_read(part, field)    (part->dkstats.field)
 
-#define __disk_stat_sub(gendiskp, field, subnd) \
-               __disk_stat_add(gendiskp, field, -subnd)
-#define disk_stat_sub(gendiskp, field, subnd) \
-               disk_stat_add(gendiskp, field, -subnd)
+static inline void part_stat_set_all(struct hd_struct *part, int value)
+{
+       memset(&part->dkstats, value, sizeof(struct disk_stats));
+}
 
+#endif /* CONFIG_SMP */
+
+#define disk_stat_dec(cpu, gendiskp, field)                            \
+       disk_stat_add(cpu, gendiskp, field, -1)
+#define disk_stat_inc(cpu, gendiskp, field)                            \
+       disk_stat_add(cpu, gendiskp, field, 1)
+#define disk_stat_sub(cpu, gendiskp, field, subnd)                     \
+       disk_stat_add(cpu, gendiskp, field, -subnd)
+
+#define part_stat_dec(cpu, gendiskp, field)                            \
+       part_stat_add(cpu, gendiskp, field, -1)
+#define part_stat_inc(cpu, gendiskp, field)                            \
+       part_stat_add(cpu, gendiskp, field, 1)
+#define part_stat_sub(cpu, gendiskp, field, subnd)                     \
+       part_stat_add(cpu, gendiskp, field, -subnd)
+
+#define all_stat_dec(cpu, gendiskp, field, sector)                     \
+       all_stat_add(cpu, gendiskp, field, -1, sector)
+#define all_stat_inc(cpu, gendiskp, part, field, sector)               \
+       all_stat_add(cpu, gendiskp, part, field, 1, sector)
+#define all_stat_sub(cpu, gendiskp, part, field, subnd, sector)                \
+       all_stat_add(cpu, gendiskp, part, field, -subnd, sector)
 
 /* Inlines to alloc and free disk stats in struct gendisk */
 #ifdef  CONFIG_SMP
@@ -219,6 +351,20 @@ static inline void free_disk_stats(struct gendisk *disk)
 {
        free_percpu(disk->dkstats);
 }
+
+static inline int init_part_stats(struct hd_struct *part)
+{
+       part->dkstats = alloc_percpu(struct disk_stats);
+       if (!part->dkstats)
+               return 0;
+       return 1;
+}
+
+static inline void free_part_stats(struct hd_struct *part)
+{
+       free_percpu(part->dkstats);
+}
+
 #else  /* CONFIG_SMP */
 static inline int init_disk_stats(struct gendisk *disk)
 {
@@ -228,43 +374,57 @@ static inline int init_disk_stats(struct gendisk *disk)
 static inline void free_disk_stats(struct gendisk *disk)
 {
 }
+
+static inline int init_part_stats(struct hd_struct *part)
+{
+       return 1;
+}
+
+static inline void free_part_stats(struct hd_struct *part)
+{
+}
 #endif /* CONFIG_SMP */
 
 /* drivers/block/ll_rw_blk.c */
-extern void disk_round_stats(struct gendisk *disk);
+extern void disk_round_stats(int cpu, struct gendisk *disk);
+extern void part_round_stats(int cpu, struct hd_struct *part);
 
 /* drivers/block/genhd.c */
 extern int get_blkdev_list(char *, int);
 extern void add_disk(struct gendisk *disk);
 extern void del_gendisk(struct gendisk *gp);
 extern void unlink_gendisk(struct gendisk *gp);
-extern struct gendisk *get_gendisk(dev_t dev, int *part);
+extern struct gendisk *get_gendisk(dev_t dev, int *partno);
+extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
 
 extern void set_device_ro(struct block_device *bdev, int flag);
 extern void set_disk_ro(struct gendisk *disk, int flag);
 
+static inline int get_disk_ro(struct gendisk *disk)
+{
+       return disk->part0.policy;
+}
+
 /* drivers/char/random.c */
 extern void add_disk_randomness(struct gendisk *disk);
 extern void rand_initialize_disk(struct gendisk *disk);
 
 static inline sector_t get_start_sect(struct block_device *bdev)
 {
-       return bdev->bd_contains == bdev ? 0 : bdev->bd_part->start_sect;
+       return bdev->bd_part->start_sect;
 }
 static inline sector_t get_capacity(struct gendisk *disk)
 {
-       return disk->capacity;
+       return disk->part0.nr_sects;
 }
 static inline void set_capacity(struct gendisk *disk, sector_t size)
 {
-       disk->capacity = size;
+       disk->part0.nr_sects = size;
 }
 
-#endif  /*  __KERNEL__  */
-
 #ifdef CONFIG_SOLARIS_X86_PARTITION
 
-#define SOLARIS_X86_NUMSLICE   8
+#define SOLARIS_X86_NUMSLICE   16
 #define SOLARIS_X86_VTOC_SANE  (0x600DDEEEUL)
 
 struct solaris_x86_slice {
@@ -405,42 +565,54 @@ struct unixware_disklabel {
 #   define MINIX_NR_SUBPARTITIONS  4
 #endif /* CONFIG_MINIX_SUBPARTITION */
 
-#ifdef __KERNEL__
-
 #define ADDPART_FLAG_NONE      0
 #define ADDPART_FLAG_RAID      1
 #define ADDPART_FLAG_WHOLEDISK 2
 
-char *disk_name (struct gendisk *hd, int part, char *buf);
+extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
+extern void blk_free_devt(dev_t devt);
+extern dev_t blk_lookup_devt(const char *name, int partno);
+extern char *disk_name (struct gendisk *hd, int partno, char *buf);
 
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
-extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
+extern int __must_check add_partition(struct gendisk *, int, sector_t, sector_t, int);
 extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
 extern struct gendisk *alloc_disk_node(int minors, int node_id);
 extern struct gendisk *alloc_disk(int minors);
+extern struct gendisk *alloc_disk_ext_node(int minors, int ext_minrs,
+                                          int node_id);
+extern struct gendisk *alloc_disk_ext(int minors, int ext_minors);
 extern struct kobject *get_disk(struct gendisk *disk);
 extern void put_disk(struct gendisk *disk);
-extern void genhd_media_change_notify(struct gendisk *disk);
-extern void blk_register_region(dev_t dev, unsigned long range,
+extern void blk_register_region(dev_t devt, unsigned long range,
                        struct module *module,
                        struct kobject *(*probe)(dev_t, int *, void *),
                        int (*lock)(dev_t, void *),
                        void *data);
-extern void blk_unregister_region(dev_t dev, unsigned long range);
-
-static inline struct block_device *bdget_disk(struct gendisk *disk, int index)
-{
-       return bdget(MKDEV(disk->major, disk->first_minor) + index);
-}
+extern void blk_unregister_region(dev_t devt, unsigned long range);
 
-#endif
+extern ssize_t part_size_show(struct device *dev,
+                             struct device_attribute *attr, char *buf);
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+extern ssize_t part_fail_show(struct device *dev,
+                             struct device_attribute *attr, char *buf);
+extern ssize_t part_fail_store(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count);
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
 
 #else /* CONFIG_BLOCK */
 
 static inline void printk_all_partitions(void) { }
 
+static inline dev_t blk_lookup_devt(const char *name, int partno)
+{
+       dev_t devt = MKDEV(0, 0);
+       return devt;
+}
+
 #endif /* CONFIG_BLOCK */
 
-#endif
+#endif /* _LINUX_GENHD_H */