blob: eb5ba63805ddcb849dbf5048026cdd03e61f3556 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#ifndef _LINUX_GENHD_H
3#define _LINUX_GENHD_H
4
5/*
6 * genhd.h Copyright (C) 1992 Drew Eckhardt
7 * Generic hard disk header file by
8 * Drew Eckhardt
9 *
10 * <drew@colorado.edu>
11 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/types.h>
Kay Sieversedfaa7c2007-05-21 22:08:01 +020014#include <linux/kdev_t.h>
Tejun Heoe71bf0d2008-09-03 09:03:02 +020015#include <linux/rcupdate.h>
Will Drewry6d1d8052010-08-31 15:47:05 -050016#include <linux/slab.h>
Ming Lei6c710132015-07-16 11:16:45 +080017#include <linux/percpu-refcount.h>
Andy Shevchenko63579782016-05-20 17:01:24 -070018#include <linux/uuid.h>
Michael Callahandbae2c52018-07-18 04:47:38 -070019#include <linux/blk_types.h>
Greg Kroah-Hartman1df9ac62020-05-02 09:37:37 +020020#include <linux/android_kabi.h>
Mikulas Patocka1226b8d2018-12-06 11:41:20 -050021#include <asm/local.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
David Howells93614012006-09-30 20:45:40 +020023#ifdef CONFIG_BLOCK
24
Tejun Heo548b10e2008-08-29 09:01:47 +020025#define dev_to_disk(device) container_of((device), struct gendisk, part0.__dev)
Tejun Heoed9e1982008-08-25 19:56:05 +090026#define dev_to_part(device) container_of((device), struct hd_struct, __dev)
Tejun Heo548b10e2008-08-29 09:01:47 +020027#define disk_to_dev(disk) (&(disk)->part0.__dev)
Tejun Heoed9e1982008-08-25 19:56:05 +090028#define part_to_dev(part) (&((part)->__dev))
Kay Sieversedfaa7c2007-05-21 22:08:01 +020029
Kay Sieversedfaa7c2007-05-21 22:08:01 +020030extern struct device_type part_type;
31extern struct kobject *block_depr;
32extern struct class block_class;
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034enum {
35/* These three have identical behaviour; use the second one if DOS FDISK gets
36 confused about extended/logical partitions starting past cylinder 1023. */
37 DOS_EXTENDED_PARTITION = 5,
38 LINUX_EXTENDED_PARTITION = 0x85,
39 WIN98_EXTENDED_PARTITION = 0x0f,
40
Fabio Massimo Di Nittod18d7682007-02-10 23:50:00 -080041 SUN_WHOLE_DISK = DOS_EXTENDED_PARTITION,
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 LINUX_SWAP_PARTITION = 0x82,
Olaf Hering4419d1a2007-02-10 01:45:47 -080044 LINUX_DATA_PARTITION = 0x83,
45 LINUX_LVM_PARTITION = 0x8e,
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 LINUX_RAID_PARTITION = 0xfd, /* autodetect RAID partition */
47
48 SOLARIS_X86_PARTITION = LINUX_SWAP_PARTITION,
49 NEW_SOLARIS_X86_PARTITION = 0xbf,
50
51 DM6_AUX1PARTITION = 0x51, /* no DDO: use xlated geom */
52 DM6_AUX3PARTITION = 0x53, /* no DDO: use xlated geom */
53 DM6_PARTITION = 0x54, /* has DDO: use xlated geom & offset */
54 EZD_PARTITION = 0x55, /* EZ-DRIVE */
55
56 FREEBSD_PARTITION = 0xa5, /* FreeBSD Partition ID */
57 OPENBSD_PARTITION = 0xa6, /* OpenBSD Partition ID */
58 NETBSD_PARTITION = 0xa9, /* NetBSD Partition ID */
59 BSDI_PARTITION = 0xb7, /* BSDI Partition ID */
60 MINIX_PARTITION = 0x81, /* Minix Partition ID */
61 UNIXWARE_PARTITION = 0x63, /* Same as GNU_HURD and SCO Unix */
62};
63
Tejun Heo689d6fa2008-08-25 19:56:16 +090064#define DISK_MAX_PARTS 256
Tejun Heo3e1a7ff2008-08-25 19:56:17 +090065#define DISK_NAME_LEN 32
Tejun Heo689d6fa2008-08-25 19:56:16 +090066
David Woodhouse34186ef2006-04-25 14:07:57 +010067#include <linux/major.h>
68#include <linux/device.h>
69#include <linux/smp.h>
70#include <linux/string.h>
71#include <linux/fs.h>
Kristen Carlson Accardi8ce7ad7b2007-05-23 13:57:38 -070072#include <linux/workqueue.h>
David Woodhouse34186ef2006-04-25 14:07:57 +010073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074struct partition {
75 unsigned char boot_ind; /* 0x80 - active */
76 unsigned char head; /* starting head */
77 unsigned char sector; /* starting sector */
78 unsigned char cyl; /* starting cylinder */
79 unsigned char sys_ind; /* What partition type */
80 unsigned char end_head; /* end head */
81 unsigned char end_sector; /* end sector */
82 unsigned char end_cyl; /* end cylinder */
83 __le32 start_sect; /* starting sector counting from 0 */
84 __le32 nr_sects; /* nr of sectors in partition */
85} __attribute__((packed));
86
Jerome Marchandea5c48a2008-02-08 11:04:09 +010087struct disk_stats {
Omar Sandovalb57e99b2018-09-21 16:44:34 -070088 u64 nsecs[NR_STAT_GROUPS];
Michael Callahandbae2c52018-07-18 04:47:38 -070089 unsigned long sectors[NR_STAT_GROUPS];
90 unsigned long ios[NR_STAT_GROUPS];
91 unsigned long merges[NR_STAT_GROUPS];
Jerome Marchandea5c48a2008-02-08 11:04:09 +010092 unsigned long io_ticks;
93 unsigned long time_in_queue;
Mikulas Patocka1226b8d2018-12-06 11:41:20 -050094 local_t in_flight[2];
Jerome Marchandea5c48a2008-02-08 11:04:09 +010095};
Will Drewry6d1d8052010-08-31 15:47:05 -050096
97#define PARTITION_META_INFO_VOLNAMELTH 64
Stephen Warren1ad7e892012-11-08 16:12:25 -080098/*
99 * Enough for the string representation of any kind of UUID plus NULL.
100 * EFI UUID is 36 characters. MSDOS UUID is 11 characters.
101 */
Andy Shevchenko63579782016-05-20 17:01:24 -0700102#define PARTITION_META_INFO_UUIDLTH (UUID_STRING_LEN + 1)
Will Drewry6d1d8052010-08-31 15:47:05 -0500103
104struct partition_meta_info {
Stephen Warren1ad7e892012-11-08 16:12:25 -0800105 char uuid[PARTITION_META_INFO_UUIDLTH];
Will Drewry6d1d8052010-08-31 15:47:05 -0500106 u8 volname[PARTITION_META_INFO_VOLNAMELTH];
107};
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109struct hd_struct {
110 sector_t start_sect;
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200111 /*
112 * nr_sects is protected by sequence counter. One might extend a
113 * partition while IO is happening to it and update of nr_sects
114 * can be non-atomic on 32bit machines with 64bit sector_t.
115 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 sector_t nr_sects;
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200117 seqcount_t nr_sects_seq;
Martin K. Petersenc72758f2009-05-22 17:17:53 -0400118 sector_t alignment_offset;
Jens Axboea1706ac2011-05-30 07:42:51 +0200119 unsigned int discard_alignment;
Tejun Heoed9e1982008-08-25 19:56:05 +0900120 struct device __dev;
Jun'ichi Nomura6a4d44c2006-03-27 01:17:55 -0800121 struct kobject *holder_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 int policy, partno;
Will Drewry6d1d8052010-08-31 15:47:05 -0500123 struct partition_meta_info *info;
Akinobu Mitac17bb492006-12-08 02:39:46 -0800124#ifdef CONFIG_FAIL_MAKE_REQUEST
125 int make_it_fail;
126#endif
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100127 unsigned long stamp;
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100128#ifdef CONFIG_SMP
Tejun Heo43cf38e2010-02-02 14:38:57 +0900129 struct disk_stats __percpu *dkstats;
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100130#else
131 struct disk_stats dkstats;
132#endif
Ming Lei6c710132015-07-16 11:16:45 +0800133 struct percpu_ref ref;
Yufen Yu94a2c3a2018-11-28 16:42:01 +0800134 struct rcu_work rcu_work;
Greg Kroah-Hartman1df9ac62020-05-02 09:37:37 +0200135
136 ANDROID_KABI_RESERVE(1);
137 ANDROID_KABI_RESERVE(2);
138 ANDROID_KABI_RESERVE(3);
139 ANDROID_KABI_RESERVE(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140};
141
142#define GENHD_FL_REMOVABLE 1
NeilBrown97fedbb2010-03-16 08:55:32 +0100143/* 2 is unused */
Kristen Carlson Accardi86ce18d2007-05-23 13:57:38 -0700144#define GENHD_FL_MEDIA_CHANGE_NOTIFY 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145#define GENHD_FL_CD 8
146#define GENHD_FL_UP 16
147#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
Tejun Heo689d6fa2008-08-25 19:56:16 +0900148#define GENHD_FL_EXT_DEVT 64 /* allow extended devt */
Bartlomiej Zolnierkiewiczdb429e92009-06-07 13:52:52 +0200149#define GENHD_FL_NATIVE_CAPACITY 128
Tejun Heod4dc2102011-04-21 20:54:46 +0200150#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE 256
Tejun Heod27769e2011-08-23 20:01:04 +0200151#define GENHD_FL_NO_PART_SCAN 512
Christoph Hellwig8ddcd652017-11-02 21:29:53 +0300152#define GENHD_FL_HIDDEN 1024
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Tejun Heo77ea8872010-12-08 20:57:37 +0100154enum {
155 DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */
156 DISK_EVENT_EJECT_REQUEST = 1 << 1, /* eject requested */
157};
158
Martin Wilckc92e2f02019-03-27 14:51:02 +0100159enum {
160 /* Poll even if events_poll_msecs is unset */
161 DISK_EVENT_FLAG_POLL = 1 << 0,
162 /* Forward events to udev */
163 DISK_EVENT_FLAG_UEVENT = 1 << 1,
164};
165
Tejun Heo540eed52008-08-25 19:56:15 +0900166struct disk_part_tbl {
167 struct rcu_head rcu_head;
168 int len;
Arnd Bergmann4d2deb42010-02-24 20:01:56 +0100169 struct hd_struct __rcu *last_lookup;
170 struct hd_struct __rcu *part[];
Tejun Heo540eed52008-08-25 19:56:15 +0900171};
172
Tejun Heo77ea8872010-12-08 20:57:37 +0100173struct disk_events;
Vishal Verma99e66082016-01-09 08:36:51 -0800174struct badblocks;
Tejun Heo77ea8872010-12-08 20:57:37 +0100175
Martin K. Petersen25520d52015-10-21 13:19:49 -0400176#if defined(CONFIG_BLK_DEV_INTEGRITY)
177
178struct blk_integrity {
Eric Biggers869ab902017-03-24 18:03:48 -0700179 const struct blk_integrity_profile *profile;
180 unsigned char flags;
181 unsigned char tuple_size;
182 unsigned char interval_exp;
183 unsigned char tag_size;
Greg Kroah-Hartman1df9ac62020-05-02 09:37:37 +0200184
185 ANDROID_KABI_RESERVE(1);
186 ANDROID_KABI_RESERVE(2);
Martin K. Petersen25520d52015-10-21 13:19:49 -0400187};
188
189#endif /* CONFIG_BLK_DEV_INTEGRITY */
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191struct gendisk {
Tejun Heo689d6fa2008-08-25 19:56:16 +0900192 /* major, first_minor and minors are input parameters only,
193 * don't use directly. Use disk_devt() and disk_max_parts().
Tejun Heof331c022008-09-03 09:01:48 +0200194 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 int major; /* major number of driver */
196 int first_minor;
197 int minors; /* maximum number of minors, =1 for
198 * disks that can't be partitioned. */
Tejun Heof331c022008-09-03 09:01:48 +0200199
Tejun Heo3e1a7ff2008-08-25 19:56:17 +0900200 char disk_name[DISK_NAME_LEN]; /* name of major driver */
Al Viro2c9ede52011-07-23 20:24:48 -0400201 char *(*devnode)(struct gendisk *gd, umode_t *mode);
Tejun Heo77ea8872010-12-08 20:57:37 +0100202
Martin Wilckc92e2f02019-03-27 14:51:02 +0100203 unsigned short events; /* supported events */
204 unsigned short event_flags; /* flags related to event processing */
Tejun Heo77ea8872010-12-08 20:57:37 +0100205
Tejun Heob5d0b9d2008-09-03 09:06:42 +0200206 /* Array of pointers to partitions indexed by partno.
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200207 * Protected with matching bdev lock but stat and other
208 * non-critical accesses use RCU. Always access through
209 * helpers.
210 */
Arnd Bergmann4d2deb42010-02-24 20:01:56 +0100211 struct disk_part_tbl __rcu *part_tbl;
Tejun Heob5d0b9d2008-09-03 09:06:42 +0200212 struct hd_struct part0;
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200213
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700214 const struct block_device_operations *fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 struct request_queue *queue;
216 void *private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 int flags;
Jan Kara56c09082018-02-26 13:01:41 +0100219 struct rw_semaphore lookup_sem;
Jun'ichi Nomura6a4d44c2006-03-27 01:17:55 -0800220 struct kobject *slave_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222 struct timer_rand_state *random;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 atomic_t sync_io; /* RAID */
Tejun Heo77ea8872010-12-08 20:57:37 +0100224 struct disk_events *ev;
Martin K. Petersen7ba1ba12008-06-30 20:04:41 +0200225#ifdef CONFIG_BLK_DEV_INTEGRITY
Martin K. Petersenaff34e12015-10-21 13:19:27 -0400226 struct kobject integrity_kobj;
Martin K. Petersen25520d52015-10-21 13:19:49 -0400227#endif /* CONFIG_BLK_DEV_INTEGRITY */
Tejun Heo540eed52008-08-25 19:56:15 +0900228 int node_id;
Vishal Verma99e66082016-01-09 08:36:51 -0800229 struct badblocks *bb;
Byungchul Parke319e1f2017-10-25 17:56:05 +0900230 struct lockdep_map lockdep_map;
Greg Kroah-Hartman1df9ac62020-05-02 09:37:37 +0200231
232 ANDROID_KABI_RESERVE(1);
233 ANDROID_KABI_RESERVE(2);
234 ANDROID_KABI_RESERVE(3);
235 ANDROID_KABI_RESERVE(4);
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237};
238
Tejun Heo310a2c12008-08-25 19:47:17 +0900239static inline struct gendisk *part_to_disk(struct hd_struct *part)
240{
Tejun Heo548b10e2008-08-29 09:01:47 +0200241 if (likely(part)) {
242 if (part->partno)
243 return dev_to_disk(part_to_dev(part)->parent);
244 else
245 return dev_to_disk(part_to_dev(part));
246 }
Tejun Heo310a2c12008-08-25 19:47:17 +0900247 return NULL;
248}
249
Tejun Heof331c022008-09-03 09:01:48 +0200250static inline int disk_max_parts(struct gendisk *disk)
251{
Tejun Heo689d6fa2008-08-25 19:56:16 +0900252 if (disk->flags & GENHD_FL_EXT_DEVT)
253 return DISK_MAX_PARTS;
254 return disk->minors;
Tejun Heob5d0b9d2008-09-03 09:06:42 +0200255}
256
Tejun Heod27769e2011-08-23 20:01:04 +0200257static inline bool disk_part_scan_enabled(struct gendisk *disk)
Tejun Heob5d0b9d2008-09-03 09:06:42 +0200258{
Tejun Heod27769e2011-08-23 20:01:04 +0200259 return disk_max_parts(disk) > 1 &&
260 !(disk->flags & GENHD_FL_NO_PART_SCAN);
Tejun Heof331c022008-09-03 09:01:48 +0200261}
262
263static inline dev_t disk_devt(struct gendisk *disk)
264{
Christoph Hellwig517bf3c2017-11-02 21:29:52 +0300265 return MKDEV(disk->major, disk->first_minor);
Tejun Heof331c022008-09-03 09:01:48 +0200266}
267
268static inline dev_t part_devt(struct hd_struct *part)
269{
Tejun Heoed9e1982008-08-25 19:56:05 +0900270 return part_to_dev(part)->devt;
Tejun Heof331c022008-09-03 09:01:48 +0200271}
272
Greg Edwards67f25192017-10-24 11:21:48 -0600273extern struct hd_struct *__disk_get_part(struct gendisk *disk, int partno);
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200274extern struct hd_struct *disk_get_part(struct gendisk *disk, int partno);
275
276static inline void disk_put_part(struct hd_struct *part)
277{
278 if (likely(part))
Tejun Heoed9e1982008-08-25 19:56:05 +0900279 put_device(part_to_dev(part));
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200280}
281
282/*
283 * Smarter partition iterator without context limits.
284 */
285#define DISK_PITER_REVERSE (1 << 0) /* iterate in the reverse direction */
286#define DISK_PITER_INCL_EMPTY (1 << 1) /* include 0-sized parts */
Tejun Heob5d0b9d2008-09-03 09:06:42 +0200287#define DISK_PITER_INCL_PART0 (1 << 2) /* include partition 0 */
Tejun Heo71982a42009-04-17 08:34:48 +0200288#define DISK_PITER_INCL_EMPTY_PART0 (1 << 3) /* include empty partition 0 */
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200289
290struct disk_part_iter {
291 struct gendisk *disk;
292 struct hd_struct *part;
293 int idx;
294 unsigned int flags;
295};
296
297extern void disk_part_iter_init(struct disk_part_iter *piter,
298 struct gendisk *disk, unsigned int flags);
299extern struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter);
300extern void disk_part_iter_exit(struct disk_part_iter *piter);
301
302extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
303 sector_t sector);
304
Tejun Heoc9959052008-08-25 19:47:21 +0900305/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 * Macros to operate on percpu disk statistics:
307 *
Tejun Heoc9959052008-08-25 19:47:21 +0900308 * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
309 * and should be called between disk_stat_lock() and
310 * disk_stat_unlock().
311 *
312 * part_stat_read() can be called at any time.
313 *
314 * part_stat_{add|set_all}() and {init|free}_part_stats are for
315 * internal use only.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 */
317#ifdef CONFIG_SMP
Tejun Heo074a7ac2008-08-25 19:56:14 +0900318#define part_stat_lock() ({ rcu_read_lock(); get_cpu(); })
319#define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0)
Tejun Heoc9959052008-08-25 19:47:21 +0900320
Mikulas Patocka1226b8d2018-12-06 11:41:20 -0500321#define part_stat_get_cpu(part, field, cpu) \
322 (per_cpu_ptr((part)->dkstats, (cpu))->field)
323
324#define part_stat_get(part, field) \
325 part_stat_get_cpu(part, field, smp_processor_id())
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100326
327#define part_stat_read(part, field) \
328({ \
Tejun Heo074a7ac2008-08-25 19:56:14 +0900329 typeof((part)->dkstats->field) res = 0; \
Stephen Hemminger7af92f82010-01-06 15:45:55 -0800330 unsigned int _cpu; \
331 for_each_possible_cpu(_cpu) \
332 res += per_cpu_ptr((part)->dkstats, _cpu)->field; \
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100333 res; \
334})
335
Jens Axboe28f13702008-05-07 10:15:46 +0200336static inline void part_stat_set_all(struct hd_struct *part, int value)
337{
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100338 int i;
Jens Axboe28f13702008-05-07 10:15:46 +0200339
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100340 for_each_possible_cpu(i)
341 memset(per_cpu_ptr(part->dkstats, i), value,
Jens Axboe28f13702008-05-07 10:15:46 +0200342 sizeof(struct disk_stats));
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100343}
Tejun Heoc9959052008-08-25 19:47:21 +0900344
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100345static inline int init_part_stats(struct hd_struct *part)
346{
347 part->dkstats = alloc_percpu(struct disk_stats);
348 if (!part->dkstats)
349 return 0;
350 return 1;
351}
352
353static inline void free_part_stats(struct hd_struct *part)
354{
355 free_percpu(part->dkstats);
356}
357
Tejun Heo074a7ac2008-08-25 19:56:14 +0900358#else /* !CONFIG_SMP */
359#define part_stat_lock() ({ rcu_read_lock(); 0; })
360#define part_stat_unlock() rcu_read_unlock()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Mikulas Patocka1226b8d2018-12-06 11:41:20 -0500362#define part_stat_get(part, field) ((part)->dkstats.field)
363#define part_stat_get_cpu(part, field, cpu) part_stat_get(part, field)
364#define part_stat_read(part, field) part_stat_get(part, field)
Tejun Heo074a7ac2008-08-25 19:56:14 +0900365
366static inline void part_stat_set_all(struct hd_struct *part, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Tejun Heo074a7ac2008-08-25 19:56:14 +0900368 memset(&part->dkstats, value, sizeof(struct disk_stats));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
Jerome Marchandea5c48a2008-02-08 11:04:09 +0100370
371static inline int init_part_stats(struct hd_struct *part)
372{
373 return 1;
374}
375
376static inline void free_part_stats(struct hd_struct *part)
377{
378}
Tejun Heo074a7ac2008-08-25 19:56:14 +0900379
380#endif /* CONFIG_SMP */
381
Omar Sandovalb57e99b2018-09-21 16:44:34 -0700382#define part_stat_read_msecs(part, which) \
383 div_u64(part_stat_read(part, nsecs[which]), NSEC_PER_MSEC)
384
Michael Callahan59767fb2018-07-18 04:47:37 -0700385#define part_stat_read_accum(part, field) \
Michael Callahandbae2c52018-07-18 04:47:38 -0700386 (part_stat_read(part, field[STAT_READ]) + \
Michael Callahanbdca3c82018-07-18 04:47:40 -0700387 part_stat_read(part, field[STAT_WRITE]) + \
388 part_stat_read(part, field[STAT_DISCARD]))
Michael Callahan59767fb2018-07-18 04:47:37 -0700389
Mikulas Patocka1226b8d2018-12-06 11:41:20 -0500390#define __part_stat_add(part, field, addnd) \
391 (part_stat_get(part, field) += (addnd))
392
Mike Snitzer112f1582018-12-06 11:41:18 -0500393#define part_stat_add(part, field, addnd) do { \
394 __part_stat_add((part), field, addnd); \
Tejun Heo074a7ac2008-08-25 19:56:14 +0900395 if ((part)->partno) \
Mike Snitzer112f1582018-12-06 11:41:18 -0500396 __part_stat_add(&part_to_disk((part))->part0, \
Tejun Heo074a7ac2008-08-25 19:56:14 +0900397 field, addnd); \
398} while (0)
399
Mike Snitzer112f1582018-12-06 11:41:18 -0500400#define part_stat_dec(gendiskp, field) \
401 part_stat_add(gendiskp, field, -1)
402#define part_stat_inc(gendiskp, field) \
403 part_stat_add(gendiskp, field, 1)
404#define part_stat_sub(gendiskp, field, subnd) \
405 part_stat_add(gendiskp, field, -subnd)
Tejun Heo074a7ac2008-08-25 19:56:14 +0900406
Mikulas Patocka1226b8d2018-12-06 11:41:20 -0500407#define part_stat_local_dec(gendiskp, field) \
408 local_dec(&(part_stat_get(gendiskp, field)))
409#define part_stat_local_inc(gendiskp, field) \
410 local_inc(&(part_stat_get(gendiskp, field)))
411#define part_stat_local_read(gendiskp, field) \
412 local_read(&(part_stat_get(gendiskp, field)))
413#define part_stat_local_read_cpu(gendiskp, field, cpu) \
414 local_read(&(part_stat_get_cpu(gendiskp, field, cpu)))
415
Mikulas Patockae016b782018-12-06 11:41:21 -0500416unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part);
Omar Sandovalbf0ddab2018-04-26 00:21:59 -0700417void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
418 unsigned int inflight[2]);
Jens Axboef299b7c2017-08-08 17:51:45 -0600419void part_dec_in_flight(struct request_queue *q, struct hd_struct *part,
420 int rw);
421void part_inc_in_flight(struct request_queue *q, struct hd_struct *part,
422 int rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Will Drewry6d1d8052010-08-31 15:47:05 -0500424static inline struct partition_meta_info *alloc_part_info(struct gendisk *disk)
425{
426 if (disk)
427 return kzalloc_node(sizeof(struct partition_meta_info),
428 GFP_KERNEL, disk->node_id);
429 return kzalloc(sizeof(struct partition_meta_info), GFP_KERNEL);
430}
431
432static inline void free_part_info(struct hd_struct *part)
433{
434 kfree(part->info);
435}
436
Konstantin Khlebnikov2334b2d2020-03-25 16:07:04 +0300437void update_io_ticks(struct hd_struct *part, unsigned long now, bool end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Petros Koutoupis32ca1632009-03-10 08:25:54 +0100439/* block/genhd.c */
Hannes Reineckefef912b2018-09-28 08:17:19 +0200440extern void device_add_disk(struct device *parent, struct gendisk *disk,
441 const struct attribute_group **groups);
Dan Williamse63a46b2016-06-15 18:17:27 -0700442static inline void add_disk(struct gendisk *disk)
443{
Hannes Reineckefef912b2018-09-28 08:17:19 +0200444 device_add_disk(NULL, disk, NULL);
Dan Williamse63a46b2016-06-15 18:17:27 -0700445}
Mike Snitzerfa70d2e2018-01-08 22:01:13 -0500446extern void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk);
447static inline void add_disk_no_queue_reg(struct gendisk *disk)
448{
449 device_add_disk_no_queue_reg(NULL, disk);
450}
Dan Williamse63a46b2016-06-15 18:17:27 -0700451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452extern void del_gendisk(struct gendisk *gp);
Tejun Heocf771cb2008-09-03 09:01:09 +0200453extern struct gendisk *get_gendisk(dev_t dev, int *partno);
Tejun Heof331c022008-09-03 09:01:48 +0200454extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456extern void set_device_ro(struct block_device *bdev, int flag);
457extern void set_disk_ro(struct gendisk *disk, int flag);
458
Tejun Heob7db9952008-08-25 19:56:10 +0900459static inline int get_disk_ro(struct gendisk *disk)
460{
461 return disk->part0.policy;
462}
463
Tejun Heo77ea8872010-12-08 20:57:37 +0100464extern void disk_block_events(struct gendisk *disk);
465extern void disk_unblock_events(struct gendisk *disk);
Tejun Heo85ef06d2011-07-01 16:17:47 +0200466extern void disk_flush_events(struct gendisk *disk, unsigned int mask);
Tejun Heo77ea8872010-12-08 20:57:37 +0100467extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask);
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469/* drivers/char/random.c */
Emese Revfy0766f782016-06-20 20:42:34 +0200470extern void add_disk_randomness(struct gendisk *disk) __latent_entropy;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471extern void rand_initialize_disk(struct gendisk *disk);
472
473static inline sector_t get_start_sect(struct block_device *bdev)
474{
Tejun Heo0762b8b2008-08-25 19:56:12 +0900475 return bdev->bd_part->start_sect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476}
477static inline sector_t get_capacity(struct gendisk *disk)
478{
Tejun Heo80795ae2008-08-25 19:56:07 +0900479 return disk->part0.nr_sects;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481static inline void set_capacity(struct gendisk *disk, sector_t size)
482{
Tejun Heo80795ae2008-08-25 19:56:07 +0900483 disk->part0.nr_sects = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486#ifdef CONFIG_SOLARIS_X86_PARTITION
487
Mark Fortescueb84d8792007-07-25 18:30:08 -0700488#define SOLARIS_X86_NUMSLICE 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL)
490
491struct solaris_x86_slice {
492 __le16 s_tag; /* ID tag of partition */
493 __le16 s_flag; /* permission flags */
494 __le32 s_start; /* start sector no of partition */
495 __le32 s_size; /* # of blocks in partition */
496};
497
498struct solaris_x86_vtoc {
499 unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */
500 __le32 v_sanity; /* to verify vtoc sanity */
501 __le32 v_version; /* layout version */
502 char v_volume[8]; /* volume name */
503 __le16 v_sectorsz; /* sector size in bytes */
504 __le16 v_nparts; /* number of partitions */
505 unsigned int v_reserved[10]; /* free space */
506 struct solaris_x86_slice
507 v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
508 unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */
509 char v_asciilabel[128]; /* for compatibility */
510};
511
512#endif /* CONFIG_SOLARIS_X86_PARTITION */
513
514#ifdef CONFIG_BSD_DISKLABEL
515/*
516 * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
517 * updated by Marc Espie <Marc.Espie@openbsd.org>
518 */
519
520/* check against BSD src/sys/sys/disklabel.h for consistency */
521
522#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
523#define BSD_MAXPARTITIONS 16
524#define OPENBSD_MAXPARTITIONS 16
525#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
526struct bsd_disklabel {
527 __le32 d_magic; /* the magic number */
528 __s16 d_type; /* drive type */
529 __s16 d_subtype; /* controller/d_type specific */
530 char d_typename[16]; /* type name, e.g. "eagle" */
531 char d_packname[16]; /* pack identifier */
532 __u32 d_secsize; /* # of bytes per sector */
533 __u32 d_nsectors; /* # of data sectors per track */
534 __u32 d_ntracks; /* # of tracks per cylinder */
535 __u32 d_ncylinders; /* # of data cylinders per unit */
536 __u32 d_secpercyl; /* # of data sectors per cylinder */
537 __u32 d_secperunit; /* # of data sectors per unit */
538 __u16 d_sparespertrack; /* # of spare sectors per track */
539 __u16 d_sparespercyl; /* # of spare sectors per cylinder */
540 __u32 d_acylinders; /* # of alt. cylinders per unit */
541 __u16 d_rpm; /* rotational speed */
542 __u16 d_interleave; /* hardware sector interleave */
543 __u16 d_trackskew; /* sector 0 skew, per track */
544 __u16 d_cylskew; /* sector 0 skew, per cylinder */
545 __u32 d_headswitch; /* head switch time, usec */
546 __u32 d_trkseek; /* track-to-track seek, usec */
547 __u32 d_flags; /* generic flags */
548#define NDDATA 5
549 __u32 d_drivedata[NDDATA]; /* drive-type specific information */
550#define NSPARE 5
551 __u32 d_spare[NSPARE]; /* reserved for future use */
552 __le32 d_magic2; /* the magic number (again) */
553 __le16 d_checksum; /* xor of data incl. partitions */
554
555 /* filesystem and partition information: */
556 __le16 d_npartitions; /* number of partitions in following */
557 __le32 d_bbsize; /* size of boot area at sn0, bytes */
558 __le32 d_sbsize; /* max size of fs superblock, bytes */
559 struct bsd_partition { /* the partition table */
560 __le32 p_size; /* number of sectors in partition */
561 __le32 p_offset; /* starting sector */
562 __le32 p_fsize; /* filesystem basic fragment size */
563 __u8 p_fstype; /* filesystem type, see below */
564 __u8 p_frag; /* filesystem fragments per block */
565 __le16 p_cpg; /* filesystem cylinders per group */
566 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
567};
568
569#endif /* CONFIG_BSD_DISKLABEL */
570
571#ifdef CONFIG_UNIXWARE_DISKLABEL
572/*
573 * Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
574 * and Krzysztof G. Baranowski <kgb@knm.org.pl>
575 */
576
577#define UNIXWARE_DISKMAGIC (0xCA5E600DUL) /* The disk magic number */
578#define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL) /* The slice table magic nr */
579#define UNIXWARE_NUMSLICE 16
580#define UNIXWARE_FS_UNUSED 0 /* Unused slice entry ID */
581
582struct unixware_slice {
583 __le16 s_label; /* label */
584 __le16 s_flags; /* permission flags */
585 __le32 start_sect; /* starting sector */
586 __le32 nr_sects; /* number of sectors in slice */
587};
588
589struct unixware_disklabel {
590 __le32 d_type; /* drive type */
591 __le32 d_magic; /* the magic number */
592 __le32 d_version; /* version number */
593 char d_serial[12]; /* serial number of the device */
594 __le32 d_ncylinders; /* # of data cylinders per device */
595 __le32 d_ntracks; /* # of tracks per cylinder */
596 __le32 d_nsectors; /* # of data sectors per track */
597 __le32 d_secsize; /* # of bytes per sector */
598 __le32 d_part_start; /* # of first sector of this partition */
599 __le32 d_unknown1[12]; /* ? */
600 __le32 d_alt_tbl; /* byte offset of alternate table */
601 __le32 d_alt_len; /* byte length of alternate table */
602 __le32 d_phys_cyl; /* # of physical cylinders per device */
603 __le32 d_phys_trk; /* # of physical tracks per cylinder */
604 __le32 d_phys_sec; /* # of physical sectors per track */
605 __le32 d_phys_bytes; /* # of physical bytes per sector */
606 __le32 d_unknown2; /* ? */
607 __le32 d_unknown3; /* ? */
608 __le32 d_pad[8]; /* pad */
609
610 struct unixware_vtoc {
611 __le32 v_magic; /* the magic number */
612 __le32 v_version; /* version number */
613 char v_name[8]; /* volume name */
614 __le16 v_nslices; /* # of slices */
615 __le16 v_unknown1; /* ? */
616 __le32 v_reserved[10]; /* reserved */
617 struct unixware_slice
618 v_slice[UNIXWARE_NUMSLICE]; /* slice headers */
619 } vtoc;
620
621}; /* 408 */
622
623#endif /* CONFIG_UNIXWARE_DISKLABEL */
624
625#ifdef CONFIG_MINIX_SUBPARTITION
626# define MINIX_NR_SUBPARTITIONS 4
627#endif /* CONFIG_MINIX_SUBPARTITION */
628
Fabio Massimo Di Nittod18d7682007-02-10 23:50:00 -0800629#define ADDPART_FLAG_NONE 0
630#define ADDPART_FLAG_RAID 1
631#define ADDPART_FLAG_WHOLEDISK 2
632
Tejun Heobcce3de2008-08-25 19:47:22 +0900633extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
634extern void blk_free_devt(dev_t devt);
Yufen Yu6fcc44d2019-04-02 20:06:34 +0800635extern void blk_invalidate_devt(dev_t devt);
Tejun Heocf771cb2008-09-03 09:01:09 +0200636extern dev_t blk_lookup_devt(const char *name, int partno);
637extern char *disk_name (struct gendisk *hd, int partno, char *buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Tejun Heo540eed52008-08-25 19:56:15 +0900639extern int disk_expand_part_tbl(struct gendisk *disk, int target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
Jun'ichi Nomurafe316bf2012-03-02 10:38:33 +0100641extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev);
Tejun Heoba329292008-11-10 15:29:58 +0900642extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
643 int partno, sector_t start,
Will Drewry6d1d8052010-08-31 15:47:05 -0500644 sector_t len, int flags,
645 struct partition_meta_info
646 *info);
Ming Lei6c710132015-07-16 11:16:45 +0800647extern void __delete_partition(struct percpu_ref *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648extern void delete_partition(struct gendisk *, int);
Dave Gilbertdd2a3452007-05-09 02:33:24 -0700649extern void printk_all_partitions(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Byungchul Parke319e1f2017-10-25 17:56:05 +0900651extern struct gendisk *__alloc_disk_node(int minors, int node_id);
Jan Kara3079c222018-02-26 13:01:38 +0100652extern struct kobject *get_disk_and_module(struct gendisk *disk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653extern void put_disk(struct gendisk *disk);
Jan Kara9df6c292018-02-26 13:01:39 +0100654extern void put_disk_and_module(struct gendisk *disk);
Kay Sieversedfaa7c2007-05-21 22:08:01 +0200655extern void blk_register_region(dev_t devt, unsigned long range,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 struct module *module,
657 struct kobject *(*probe)(dev_t, int *, void *),
658 int (*lock)(dev_t, void *),
659 void *data);
Kay Sieversedfaa7c2007-05-21 22:08:01 +0200660extern void blk_unregister_region(dev_t devt, unsigned long range);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Tejun Heoe5610522008-08-25 19:56:09 +0900662extern ssize_t part_size_show(struct device *dev,
663 struct device_attribute *attr, char *buf);
Tejun Heo074a7ac2008-08-25 19:56:14 +0900664extern ssize_t part_stat_show(struct device *dev,
665 struct device_attribute *attr, char *buf);
Nikanth Karthikesan316d3152009-10-06 20:16:55 +0200666extern ssize_t part_inflight_show(struct device *dev,
667 struct device_attribute *attr, char *buf);
Tejun Heoeddb2e22008-08-25 19:56:13 +0900668#ifdef CONFIG_FAIL_MAKE_REQUEST
669extern ssize_t part_fail_show(struct device *dev,
670 struct device_attribute *attr, char *buf);
671extern ssize_t part_fail_store(struct device *dev,
672 struct device_attribute *attr,
673 const char *buf, size_t count);
674#endif /* CONFIG_FAIL_MAKE_REQUEST */
Tejun Heoe5610522008-08-25 19:56:09 +0900675
Byungchul Parke319e1f2017-10-25 17:56:05 +0900676#define alloc_disk_node(minors, node_id) \
677({ \
678 static struct lock_class_key __key; \
679 const char *__name; \
680 struct gendisk *__disk; \
681 \
682 __name = "(gendisk_completion)"#minors"("#node_id")"; \
683 \
684 __disk = __alloc_disk_node(minors, node_id); \
685 \
686 if (__disk) \
687 lockdep_init_map(&__disk->lockdep_map, __name, &__key, 0); \
688 \
689 __disk; \
690})
691
692#define alloc_disk(minors) alloc_disk_node(minors, NUMA_NO_NODE)
693
Ming Lei6c710132015-07-16 11:16:45 +0800694static inline int hd_ref_init(struct hd_struct *part)
Jens Axboe6c23a962011-01-07 08:43:37 +0100695{
Ming Lei6c710132015-07-16 11:16:45 +0800696 if (percpu_ref_init(&part->ref, __delete_partition, 0,
697 GFP_KERNEL))
698 return -ENOMEM;
699 return 0;
Jens Axboe6c23a962011-01-07 08:43:37 +0100700}
701
702static inline void hd_struct_get(struct hd_struct *part)
703{
Ming Lei6c710132015-07-16 11:16:45 +0800704 percpu_ref_get(&part->ref);
Jens Axboe6c23a962011-01-07 08:43:37 +0100705}
706
707static inline int hd_struct_try_get(struct hd_struct *part)
708{
Ming Lei6c710132015-07-16 11:16:45 +0800709 return percpu_ref_tryget_live(&part->ref);
Jens Axboe6c23a962011-01-07 08:43:37 +0100710}
711
712static inline void hd_struct_put(struct hd_struct *part)
713{
Ming Lei6c710132015-07-16 11:16:45 +0800714 percpu_ref_put(&part->ref);
715}
716
717static inline void hd_struct_kill(struct hd_struct *part)
718{
719 percpu_ref_kill(&part->ref);
Jens Axboe6c23a962011-01-07 08:43:37 +0100720}
721
Ming Leib54e5ed2015-07-16 11:16:44 +0800722static inline void hd_free_part(struct hd_struct *part)
723{
724 free_part_stats(part);
725 free_part_info(part);
Ming Lei6c710132015-07-16 11:16:45 +0800726 percpu_ref_exit(&part->ref);
Ming Leib54e5ed2015-07-16 11:16:44 +0800727}
728
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200729/*
730 * Any access of part->nr_sects which is not protected by partition
731 * bd_mutex or gendisk bdev bd_mutex, should be done using this
732 * accessor function.
733 *
734 * Code written along the lines of i_size_read() and i_size_write().
735 * CONFIG_PREEMPT case optimizes the case of UP kernel with preemption
736 * on.
737 */
738static inline sector_t part_nr_sects_read(struct hd_struct *part)
739{
Christoph Hellwig72deb452019-04-05 18:08:59 +0200740#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200741 sector_t nr_sects;
742 unsigned seq;
743 do {
744 seq = read_seqcount_begin(&part->nr_sects_seq);
745 nr_sects = part->nr_sects;
746 } while (read_seqcount_retry(&part->nr_sects_seq, seq));
747 return nr_sects;
Christoph Hellwig72deb452019-04-05 18:08:59 +0200748#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200749 sector_t nr_sects;
750
751 preempt_disable();
752 nr_sects = part->nr_sects;
753 preempt_enable();
754 return nr_sects;
755#else
756 return part->nr_sects;
757#endif
758}
759
760/*
761 * Should be called with mutex lock held (typically bd_mutex) of partition
762 * to provide mutual exlusion among writers otherwise seqcount might be
763 * left in wrong state leaving the readers spinning infinitely.
764 */
765static inline void part_nr_sects_write(struct hd_struct *part, sector_t size)
766{
Christoph Hellwig72deb452019-04-05 18:08:59 +0200767#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
Ahmed S. Darwish859a0a92020-06-03 16:49:48 +0200768 preempt_disable();
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200769 write_seqcount_begin(&part->nr_sects_seq);
770 part->nr_sects = size;
771 write_seqcount_end(&part->nr_sects_seq);
Ahmed S. Darwish859a0a92020-06-03 16:49:48 +0200772 preempt_enable();
Christoph Hellwig72deb452019-04-05 18:08:59 +0200773#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
Vivek Goyalc83f6bf2012-08-01 12:24:18 +0200774 preempt_disable();
775 part->nr_sects = size;
776 preempt_enable();
777#else
778 part->nr_sects = size;
779#endif
780}
781
Martin K. Petersen25520d52015-10-21 13:19:49 -0400782#if defined(CONFIG_BLK_DEV_INTEGRITY)
783extern void blk_integrity_add(struct gendisk *);
784extern void blk_integrity_del(struct gendisk *);
Martin K. Petersen25520d52015-10-21 13:19:49 -0400785#else /* CONFIG_BLK_DEV_INTEGRITY */
786static inline void blk_integrity_add(struct gendisk *disk) { }
787static inline void blk_integrity_del(struct gendisk *disk) { }
Martin K. Petersen25520d52015-10-21 13:19:49 -0400788#endif /* CONFIG_BLK_DEV_INTEGRITY */
789
Jens Axboe87c1efb2007-05-11 13:29:54 +0200790#else /* CONFIG_BLOCK */
791
792static inline void printk_all_partitions(void) { }
793
Tejun Heocf771cb2008-09-03 09:01:09 +0200794static inline dev_t blk_lookup_devt(const char *name, int partno)
Kay Sieversedfaa7c2007-05-21 22:08:01 +0200795{
796 dev_t devt = MKDEV(0, 0);
797 return devt;
798}
Jens Axboe87c1efb2007-05-11 13:29:54 +0200799#endif /* CONFIG_BLOCK */
David Howells93614012006-09-30 20:45:40 +0200800
David Woodhousea8ae50b2008-03-12 17:52:56 +0100801#endif /* _LINUX_GENHD_H */