Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6140333d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://neil.brown.name/md

* 'for-linus' of git://neil.brown.name/md: (75 commits)
  md/raid10: handle further errors during fix_read_error better.
  md/raid10: Handle read errors during recovery better.
  md/raid10: simplify read error handling during recovery.
  md/raid10: record bad blocks due to write errors during resync/recovery.
  md/raid10:  attempt to fix read errors during resync/check
  md/raid10:  Handle write errors by updating badblock log.
  md/raid10: clear bad-block record when write succeeds.
  md/raid10: avoid writing to known bad blocks on known bad drives.
  md/raid10 record bad blocks as needed during recovery.
  md/raid10: avoid reading known bad blocks during resync/recovery.
  md/raid10 - avoid reading from known bad blocks - part 3
  md/raid10: avoid reading from known bad blocks - part 2
  md/raid10: avoid reading from known bad blocks - part 1
  md/raid10: Split handle_read_error out from raid10d.
  md/raid10: simplify/reindent some loops.
  md/raid5: Clear bad blocks on successful write.
  md/raid5.  Don't write to known bad block on doubtful devices.
  md/raid5: write errors should be recorded as bad blocks if possible.
  md/raid5: use bad-block log to improve handling of uncorrectable read errors.
  md/raid5: avoid reading from known bad blocks.
  ...
parents 6f56c218 58c54fcc
Loading
Loading
Loading
Loading
+23 −6
Original line number Original line Diff line number Diff line
@@ -360,18 +360,20 @@ Each directory contains:
        A file recording the current state of the device in the array
        A file recording the current state of the device in the array
	which can be a comma separated list of
	which can be a comma separated list of
	      faulty   - device has been kicked from active use due to
	      faulty   - device has been kicked from active use due to
                         a detected fault
                         a detected fault or it has unacknowledged bad
                         blocks
	      in_sync  - device is a fully in-sync member of the array
	      in_sync  - device is a fully in-sync member of the array
	      writemostly - device will only be subject to read
	      writemostly - device will only be subject to read
		         requests if there are no other options.
		         requests if there are no other options.
			 This applies only to raid1 arrays.
			 This applies only to raid1 arrays.
	      blocked  - device has failed, metadata is "external",
	      blocked  - device has failed, and the failure hasn't been
	                 and the failure hasn't been acknowledged yet.
			 acknowledged yet by the metadata handler.
			 Writes that would write to this device if
			 Writes that would write to this device if
			 it were not faulty are blocked.
			 it were not faulty are blocked.
	      spare    - device is working, but not a full member.
	      spare    - device is working, but not a full member.
			 This includes spares that are in the process
			 This includes spares that are in the process
			 of being recovered to
			 of being recovered to
	      write_error - device has ever seen a write error.
	This list may grow in future.
	This list may grow in future.
	This can be written to.
	This can be written to.
	Writing "faulty"  simulates a failure on the device.
	Writing "faulty"  simulates a failure on the device.
@@ -379,9 +381,11 @@ Each directory contains:
	Writing "writemostly" sets the writemostly flag.
	Writing "writemostly" sets the writemostly flag.
	Writing "-writemostly" clears the writemostly flag.
	Writing "-writemostly" clears the writemostly flag.
	Writing "blocked" sets the "blocked" flag.
	Writing "blocked" sets the "blocked" flag.
	Writing "-blocked" clears the "blocked" flag and allows writes
	Writing "-blocked" clears the "blocked" flags and allows writes
		to complete.
		to complete and possibly simulates an error.
	Writing "in_sync" sets the in_sync flag.
	Writing "in_sync" sets the in_sync flag.
	Writing "write_error" sets writeerrorseen flag.
	Writing "-write_error" clears writeerrorseen flag.


	This file responds to select/poll. Any change to 'faulty'
	This file responds to select/poll. Any change to 'faulty'
	or 'blocked' causes an event.
	or 'blocked' causes an event.
@@ -419,7 +423,6 @@ Each directory contains:
        written, it will be rejected.
        written, it will be rejected.


      recovery_start
      recovery_start

        When the device is not 'in_sync', this records the number of
        When the device is not 'in_sync', this records the number of
	sectors from the start of the device which are known to be
	sectors from the start of the device which are known to be
	correct.  This is normally zero, but during a recovery
	correct.  This is normally zero, but during a recovery
@@ -435,6 +438,20 @@ Each directory contains:
	Setting this to 'none' is equivalent to setting 'in_sync'.
	Setting this to 'none' is equivalent to setting 'in_sync'.
	Setting to any other value also clears the 'in_sync' flag.
	Setting to any other value also clears the 'in_sync' flag.
	
	
      bad_blocks
	This gives the list of all known bad blocks in the form of
	start address and length (in sectors respectively). If output
	is too big to fit in a page, it will be truncated. Writing
	"sector length" to this file adds new acknowledged (i.e.
	recorded to disk safely) bad blocks.

      unacknowledged_bad_blocks
	This gives the list of known-but-not-yet-saved-to-disk bad
	blocks in the same form of 'bad_blocks'. If output is too big
	to fit in a page, it will be truncated. Writing to this file
	adds bad blocks without acknowledging them. This is largely
	for testing.





An active md device will also contain and entry for each active device
An active md device will also contain and entry for each active device
+46 −91
Original line number Original line Diff line number Diff line
@@ -29,7 +29,6 @@
#include "md.h"
#include "md.h"
#include "bitmap.h"
#include "bitmap.h"


#include <linux/dm-dirty-log.h>
/* debug macros */
/* debug macros */


#define DEBUG 0
#define DEBUG 0
@@ -777,8 +776,6 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon
static inline struct page *filemap_get_page(struct bitmap *bitmap,
static inline struct page *filemap_get_page(struct bitmap *bitmap,
					    unsigned long chunk)
					    unsigned long chunk)
{
{
	if (bitmap->filemap == NULL)
		return NULL;
	if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
	if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
		return NULL;
		return NULL;
	return bitmap->filemap[file_page_index(bitmap, chunk)
	return bitmap->filemap[file_page_index(bitmap, chunk)
@@ -878,28 +875,19 @@ enum bitmap_page_attr {
static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
				enum bitmap_page_attr attr)
				enum bitmap_page_attr attr)
{
{
	if (page)
	__set_bit((page->index<<2) + attr, bitmap->filemap_attr);
	__set_bit((page->index<<2) + attr, bitmap->filemap_attr);
	else
		__set_bit(attr, &bitmap->logattrs);
}
}


static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
				enum bitmap_page_attr attr)
				enum bitmap_page_attr attr)
{
{
	if (page)
	__clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
	__clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
	else
		__clear_bit(attr, &bitmap->logattrs);
}
}


static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
					   enum bitmap_page_attr attr)
					   enum bitmap_page_attr attr)
{
{
	if (page)
	return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
	return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
	else
		return test_bit(attr, &bitmap->logattrs);
}
}


/*
/*
@@ -912,15 +900,12 @@ static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *p
static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
{
{
	unsigned long bit;
	unsigned long bit;
	struct page *page = NULL;
	struct page *page;
	void *kaddr;
	void *kaddr;
	unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);
	unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);


	if (!bitmap->filemap) {
	if (!bitmap->filemap)
		struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log;
		return;
		if (log)
			log->type->mark_region(log, chunk);
	} else {


	page = filemap_get_page(bitmap, chunk);
	page = filemap_get_page(bitmap, chunk);
	if (!page)
	if (!page)
@@ -932,10 +917,9 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
	if (bitmap->flags & BITMAP_HOSTENDIAN)
	if (bitmap->flags & BITMAP_HOSTENDIAN)
		set_bit(bit, kaddr);
		set_bit(bit, kaddr);
	else
	else
			__test_and_set_bit_le(bit, kaddr);
		__set_bit_le(bit, kaddr);
	kunmap_atomic(kaddr, KM_USER0);
	kunmap_atomic(kaddr, KM_USER0);
	PRINTK("set file bit %lu page %lu\n", bit, page->index);
	PRINTK("set file bit %lu page %lu\n", bit, page->index);
	}
	/* record page number so it gets flushed to disk when unplug occurs */
	/* record page number so it gets flushed to disk when unplug occurs */
	set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
	set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
}
}
@@ -952,16 +936,6 @@ void bitmap_unplug(struct bitmap *bitmap)


	if (!bitmap)
	if (!bitmap)
		return;
		return;
	if (!bitmap->filemap) {
		/* Must be using a dirty_log */
		struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log;
		dirty = test_and_clear_bit(BITMAP_PAGE_DIRTY, &bitmap->logattrs);
		need_write = test_and_clear_bit(BITMAP_PAGE_NEEDWRITE, &bitmap->logattrs);
		if (dirty || need_write)
			if (log->type->flush(log))
				bitmap->flags |= BITMAP_WRITE_ERROR;
		goto out;
	}


	/* look at each page to see if there are any set bits that need to be
	/* look at each page to see if there are any set bits that need to be
	 * flushed out to disk */
	 * flushed out to disk */
@@ -990,7 +964,6 @@ void bitmap_unplug(struct bitmap *bitmap)
		else
		else
			md_super_wait(bitmap->mddev);
			md_super_wait(bitmap->mddev);
	}
	}
out:
	if (bitmap->flags & BITMAP_WRITE_ERROR)
	if (bitmap->flags & BITMAP_WRITE_ERROR)
		bitmap_file_kick(bitmap);
		bitmap_file_kick(bitmap);
}
}
@@ -1199,7 +1172,6 @@ void bitmap_daemon_work(mddev_t *mddev)
	struct page *page = NULL, *lastpage = NULL;
	struct page *page = NULL, *lastpage = NULL;
	sector_t blocks;
	sector_t blocks;
	void *paddr;
	void *paddr;
	struct dm_dirty_log *log = mddev->bitmap_info.log;


	/* Use a mutex to guard daemon_work against
	/* Use a mutex to guard daemon_work against
	 * bitmap_destroy.
	 * bitmap_destroy.
@@ -1224,11 +1196,10 @@ void bitmap_daemon_work(mddev_t *mddev)
	spin_lock_irqsave(&bitmap->lock, flags);
	spin_lock_irqsave(&bitmap->lock, flags);
	for (j = 0; j < bitmap->chunks; j++) {
	for (j = 0; j < bitmap->chunks; j++) {
		bitmap_counter_t *bmc;
		bitmap_counter_t *bmc;
		if (!bitmap->filemap) {
		if (!bitmap->filemap)
			if (!log)
			/* error or shutdown */
			/* error or shutdown */
			break;
			break;
		} else

		page = filemap_get_page(bitmap, j);
		page = filemap_get_page(bitmap, j);


		if (page != lastpage) {
		if (page != lastpage) {
@@ -1298,17 +1269,16 @@ void bitmap_daemon_work(mddev_t *mddev)
						  -1);
						  -1);


				/* clear the bit */
				/* clear the bit */
				if (page) {
				paddr = kmap_atomic(page, KM_USER0);
				paddr = kmap_atomic(page, KM_USER0);
				if (bitmap->flags & BITMAP_HOSTENDIAN)
				if (bitmap->flags & BITMAP_HOSTENDIAN)
					clear_bit(file_page_offset(bitmap, j),
					clear_bit(file_page_offset(bitmap, j),
						  paddr);
						  paddr);
				else
				else
						__test_and_clear_bit_le(file_page_offset(bitmap, j),
					__clear_bit_le(
							file_page_offset(bitmap,
									 j),
							paddr);
							paddr);
				kunmap_atomic(paddr, KM_USER0);
				kunmap_atomic(paddr, KM_USER0);
				} else
					log->type->clear_region(log, j);
			}
			}
		} else
		} else
			j |= PAGE_COUNTER_MASK;
			j |= PAGE_COUNTER_MASK;
@@ -1316,16 +1286,12 @@ void bitmap_daemon_work(mddev_t *mddev)
	spin_unlock_irqrestore(&bitmap->lock, flags);
	spin_unlock_irqrestore(&bitmap->lock, flags);


	/* now sync the final page */
	/* now sync the final page */
	if (lastpage != NULL || log != NULL) {
	if (lastpage != NULL) {
		spin_lock_irqsave(&bitmap->lock, flags);
		spin_lock_irqsave(&bitmap->lock, flags);
		if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
		if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
			clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			spin_unlock_irqrestore(&bitmap->lock, flags);
			spin_unlock_irqrestore(&bitmap->lock, flags);
			if (lastpage)
			write_page(bitmap, lastpage, 0);
			write_page(bitmap, lastpage, 0);
			else
				if (log->type->flush(log))
					bitmap->flags |= BITMAP_WRITE_ERROR;
		} else {
		} else {
			set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			spin_unlock_irqrestore(&bitmap->lock, flags);
			spin_unlock_irqrestore(&bitmap->lock, flags);
@@ -1767,12 +1733,10 @@ int bitmap_create(mddev_t *mddev)
	BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
	BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);


	if (!file
	if (!file
	    && !mddev->bitmap_info.offset
	    && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
	    && !mddev->bitmap_info.log) /* bitmap disabled, nothing to do */
		return 0;
		return 0;


	BUG_ON(file && mddev->bitmap_info.offset);
	BUG_ON(file && mddev->bitmap_info.offset);
	BUG_ON(mddev->bitmap_info.offset && mddev->bitmap_info.log);


	bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
	bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
	if (!bitmap)
	if (!bitmap)
@@ -1863,6 +1827,7 @@ int bitmap_create(mddev_t *mddev)
int bitmap_load(mddev_t *mddev)
int bitmap_load(mddev_t *mddev)
{
{
	int err = 0;
	int err = 0;
	sector_t start = 0;
	sector_t sector = 0;
	sector_t sector = 0;
	struct bitmap *bitmap = mddev->bitmap;
	struct bitmap *bitmap = mddev->bitmap;


@@ -1881,16 +1846,6 @@ int bitmap_load(mddev_t *mddev)
	}
	}
	bitmap_close_sync(bitmap);
	bitmap_close_sync(bitmap);


	if (mddev->bitmap_info.log) {
		unsigned long i;
		struct dm_dirty_log *log = mddev->bitmap_info.log;
		for (i = 0; i < bitmap->chunks; i++)
			if (!log->type->in_sync(log, i, 1))
				bitmap_set_memory_bits(bitmap,
						       (sector_t)i << CHUNK_BLOCK_SHIFT(bitmap),
						       1);
	} else {
		sector_t start = 0;
	if (mddev->degraded == 0
	if (mddev->degraded == 0
	    || bitmap->events_cleared == mddev->events)
	    || bitmap->events_cleared == mddev->events)
		/* no need to keep dirty bits to optimise a
		/* no need to keep dirty bits to optimise a
@@ -1898,7 +1853,7 @@ int bitmap_load(mddev_t *mddev)
		start = mddev->recovery_cp;
		start = mddev->recovery_cp;


	err = bitmap_init_from_disk(bitmap, start);
	err = bitmap_init_from_disk(bitmap, start);
	}

	if (err)
	if (err)
		goto out;
		goto out;


+0 −5
Original line number Original line Diff line number Diff line
@@ -212,10 +212,6 @@ struct bitmap {
	unsigned long file_pages; /* number of pages in the file */
	unsigned long file_pages; /* number of pages in the file */
	int last_page_size; /* bytes in the last page */
	int last_page_size; /* bytes in the last page */


	unsigned long logattrs; /* used when filemap_attr doesn't exist
				 * because we are working with a dirty_log
				 */

	unsigned long flags;
	unsigned long flags;


	int allclean;
	int allclean;
@@ -237,7 +233,6 @@ struct bitmap {
	wait_queue_head_t behind_wait;
	wait_queue_head_t behind_wait;


	struct sysfs_dirent *sysfs_can_clear;
	struct sysfs_dirent *sysfs_can_clear;

};
};


/* the bitmap API */
/* the bitmap API */
+785 −86

File changed.

Preview size limit exceeded, changes collapsed.

+98 −12
Original line number Original line Diff line number Diff line
@@ -29,6 +29,13 @@
typedef struct mddev_s mddev_t;
typedef struct mddev_s mddev_t;
typedef struct mdk_rdev_s mdk_rdev_t;
typedef struct mdk_rdev_s mdk_rdev_t;


/* Bad block numbers are stored sorted in a single page.
 * 64bits is used for each block or extent.
 * 54 bits are sector number, 9 bits are extent size,
 * 1 bit is an 'acknowledged' flag.
 */
#define MD_MAX_BADBLOCKS	(PAGE_SIZE/8)

/*
/*
 * MD's 'extended' device
 * MD's 'extended' device
 */
 */
@@ -48,7 +55,7 @@ struct mdk_rdev_s
	struct block_device *meta_bdev;
	struct block_device *meta_bdev;
	struct block_device *bdev;	/* block device handle */
	struct block_device *bdev;	/* block device handle */


	struct page	*sb_page;
	struct page	*sb_page, *bb_page;
	int		sb_loaded;
	int		sb_loaded;
	__u64		sb_events;
	__u64		sb_events;
	sector_t	data_offset;	/* start of data in array */
	sector_t	data_offset;	/* start of data in array */
@@ -74,9 +81,29 @@ struct mdk_rdev_s
#define	In_sync		2		/* device is in_sync with rest of array */
#define	In_sync		2		/* device is in_sync with rest of array */
#define	WriteMostly	4		/* Avoid reading if at all possible */
#define	WriteMostly	4		/* Avoid reading if at all possible */
#define	AutoDetected	7		/* added by auto-detect */
#define	AutoDetected	7		/* added by auto-detect */
#define Blocked		8		/* An error occurred on an externally
#define Blocked		8		/* An error occurred but has not yet
					 * managed array, don't allow writes
					 * been acknowledged by the metadata
					 * handler, so don't allow writes
					 * until it is cleared */
					 * until it is cleared */
#define WriteErrorSeen	9		/* A write error has been seen on this
					 * device
					 */
#define FaultRecorded	10		/* Intermediate state for clearing
					 * Blocked.  The Fault is/will-be
					 * recorded in the metadata, but that
					 * metadata hasn't been stored safely
					 * on disk yet.
					 */
#define BlockedBadBlocks 11		/* A writer is blocked because they
					 * found an unacknowledged bad-block.
					 * This can safely be cleared at any
					 * time, and the writer will re-check.
					 * It may be set at any time, and at
					 * worst the writer will timeout and
					 * re-check.  So setting it as
					 * accurately as possible is good, but
					 * not absolutely critical.
					 */
	wait_queue_head_t blocked_wait;
	wait_queue_head_t blocked_wait;


	int desc_nr;			/* descriptor index in the superblock */
	int desc_nr;			/* descriptor index in the superblock */
@@ -111,8 +138,54 @@ struct mdk_rdev_s


	struct sysfs_dirent *sysfs_state; /* handle for 'state'
	struct sysfs_dirent *sysfs_state; /* handle for 'state'
					   * sysfs entry */
					   * sysfs entry */

	struct badblocks {
		int	count;		/* count of bad blocks */
		int	unacked_exist;	/* there probably are unacknowledged
					 * bad blocks.  This is only cleared
					 * when a read discovers none
					 */
		int	shift;		/* shift from sectors to block size
					 * a -ve shift means badblocks are
					 * disabled.*/
		u64	*page;		/* badblock list */
		int	changed;
		seqlock_t lock;

		sector_t sector;
		sector_t size;		/* in sectors */
	} badblocks;
};
};


#define BB_LEN_MASK	(0x00000000000001FFULL)
#define BB_OFFSET_MASK	(0x7FFFFFFFFFFFFE00ULL)
#define BB_ACK_MASK	(0x8000000000000000ULL)
#define BB_MAX_LEN	512
#define BB_OFFSET(x)	(((x) & BB_OFFSET_MASK) >> 9)
#define BB_LEN(x)	(((x) & BB_LEN_MASK) + 1)
#define BB_ACK(x)	(!!((x) & BB_ACK_MASK))
#define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63))

extern int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
			  sector_t *first_bad, int *bad_sectors);
static inline int is_badblock(mdk_rdev_t *rdev, sector_t s, int sectors,
			      sector_t *first_bad, int *bad_sectors)
{
	if (unlikely(rdev->badblocks.count)) {
		int rv = md_is_badblock(&rdev->badblocks, rdev->data_offset + s,
					sectors,
					first_bad, bad_sectors);
		if (rv)
			*first_bad -= rdev->data_offset;
		return rv;
	}
	return 0;
}
extern int rdev_set_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors,
			      int acknowledged);
extern int rdev_clear_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors);
extern void md_ack_all_badblocks(struct badblocks *bb);

struct mddev_s
struct mddev_s
{
{
	void				*private;
	void				*private;
@@ -239,9 +312,12 @@ struct mddev_s
#define	MD_RECOVERY_FROZEN	9
#define	MD_RECOVERY_FROZEN	9


	unsigned long			recovery;
	unsigned long			recovery;
	int				recovery_disabled; /* if we detect that recovery
	/* If a RAID personality determines that recovery (of a particular
							    * will always fail, set this
	 * device) will fail due to a read error on the source device, it
							    * so we don't loop trying */
	 * takes a copy of this number and does not attempt recovery again
	 * until this number changes.
	 */
	int				recovery_disabled;


	int				in_sync;	/* know to not need resync */
	int				in_sync;	/* know to not need resync */
	/* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so
	/* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so
@@ -304,11 +380,6 @@ struct mddev_s
							 * hot-adding a bitmap.  It should
							 * hot-adding a bitmap.  It should
							 * eventually be settable by sysfs.
							 * eventually be settable by sysfs.
							 */
							 */
		/* When md is serving under dm, it might use a
		 * dirty_log to store the bits.
		 */
		struct dm_dirty_log *log;

		struct mutex		mutex;
		struct mutex		mutex;
		unsigned long		chunksize;
		unsigned long		chunksize;
		unsigned long		daemon_sleep; /* how many jiffies between updates? */
		unsigned long		daemon_sleep; /* how many jiffies between updates? */
@@ -413,6 +484,20 @@ static inline char * mdname (mddev_t * mddev)
	return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
	return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
}
}


static inline int sysfs_link_rdev(mddev_t *mddev, mdk_rdev_t *rdev)
{
	char nm[20];
	sprintf(nm, "rd%d", rdev->raid_disk);
	return sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
}

static inline void sysfs_unlink_rdev(mddev_t *mddev, mdk_rdev_t *rdev)
{
	char nm[20];
	sprintf(nm, "rd%d", rdev->raid_disk);
	sysfs_remove_link(&mddev->kobj, nm);
}

/*
/*
 * iterates through some rdev ringlist. It's safe to remove the
 * iterates through some rdev ringlist. It's safe to remove the
 * current 'rdev'. Dont touch 'tmp' though.
 * current 'rdev'. Dont touch 'tmp' though.
@@ -505,7 +590,7 @@ extern void mddev_init(mddev_t *mddev);
extern int md_run(mddev_t *mddev);
extern int md_run(mddev_t *mddev);
extern void md_stop(mddev_t *mddev);
extern void md_stop(mddev_t *mddev);
extern void md_stop_writes(mddev_t *mddev);
extern void md_stop_writes(mddev_t *mddev);
extern void md_rdev_init(mdk_rdev_t *rdev);
extern int md_rdev_init(mdk_rdev_t *rdev);


extern void mddev_suspend(mddev_t *mddev);
extern void mddev_suspend(mddev_t *mddev);
extern void mddev_resume(mddev_t *mddev);
extern void mddev_resume(mddev_t *mddev);
@@ -514,4 +599,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
				   mddev_t *mddev);
				   mddev_t *mddev);
extern int mddev_check_plugged(mddev_t *mddev);
extern int mddev_check_plugged(mddev_t *mddev);
extern void md_trim_bio(struct bio *bio, int offset, int size);
#endif /* _MD_MD_H */
#endif /* _MD_MD_H */
Loading