Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

aoe: user can ask driver to forget previously detected devices

When an AoE device is detected, the kernel is informed, and a new block device
is created. If the device is unused, the block device corresponding to remote
device that is no longer available may be removed from the system by telling
the aoe driver to "flush" its list of devices.

Without this patch, software like GPFS and LVM may attempt to read from AoE
devices that were discovered earlier but are no longer present, blocking until
the I/O attempt times out.

Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Ed L. Cashin and committed by
Linus Torvalds
262bf541 cf446f0d

+77 -19
+2
Documentation/aoe/mkdevs.sh
··· 29 29 mknod -m 0200 $dir/interfaces c $MAJOR 4 30 30 rm -f $dir/revalidate 31 31 mknod -m 0200 $dir/revalidate c $MAJOR 5 32 + rm -f $dir/flush 33 + mknod -m 0200 $dir/flush c $MAJOR 6 32 34 33 35 export n_partitions 34 36 mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
+1
Documentation/aoe/udev.txt
··· 20 20 SUBSYSTEM=="aoe", KERNEL=="err", NAME="etherd/%k", GROUP="disk", MODE="0440" 21 21 SUBSYSTEM=="aoe", KERNEL=="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" 22 22 SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220" 23 + SUBSYSTEM=="aoe", KERNEL=="flush", NAME="etherd/%k", GROUP="disk", MODE="0220" 23 24 24 25 # aoe block devices 25 26 KERNEL=="etherd*", NAME="%k", GROUP="disk"
+1
drivers/block/aoe/aoe.h
··· 191 191 struct aoedev *aoedev_by_sysminor_m(ulong sysminor); 192 192 void aoedev_downdev(struct aoedev *d); 193 193 int aoedev_isbusy(struct aoedev *d); 194 + int aoedev_flush(const char __user *str, size_t size); 194 195 195 196 int aoenet_init(void); 196 197 void aoenet_exit(void);
+5
drivers/block/aoe/aoechr.c
··· 15 15 MINOR_DISCOVER, 16 16 MINOR_INTERFACES, 17 17 MINOR_REVALIDATE, 18 + MINOR_FLUSH, 18 19 MSGSZ = 2048, 19 20 NMSG = 100, /* message backlog to retain */ 20 21 }; ··· 44 43 { MINOR_DISCOVER, "discover" }, 45 44 { MINOR_INTERFACES, "interfaces" }, 46 45 { MINOR_REVALIDATE, "revalidate" }, 46 + { MINOR_FLUSH, "flush" }, 47 47 }; 48 48 49 49 static int ··· 160 158 break; 161 159 case MINOR_REVALIDATE: 162 160 ret = revalidate(buf, cnt); 161 + break; 162 + case MINOR_FLUSH: 163 + ret = aoedev_flush(buf, cnt); 163 164 } 164 165 if (ret == 0) 165 166 ret = cnt;
+68 -19
drivers/block/aoe/aoedev.c
··· 9 9 #include <linux/netdevice.h> 10 10 #include "aoe.h" 11 11 12 + static void dummy_timer(ulong); 13 + static void aoedev_freedev(struct aoedev *); 14 + static void freetgt(struct aoetgt *t); 15 + 12 16 static struct aoedev *devlist; 13 17 static spinlock_t devlist_lock; 14 18 ··· 112 108 d->flags &= ~DEVFL_UP; 113 109 } 114 110 111 + static void 112 + aoedev_freedev(struct aoedev *d) 113 + { 114 + struct aoetgt **t, **e; 115 + 116 + if (d->gd) { 117 + aoedisk_rm_sysfs(d); 118 + del_gendisk(d->gd); 119 + put_disk(d->gd); 120 + } 121 + t = d->targets; 122 + e = t + NTARGETS; 123 + for (; t < e && *t; t++) 124 + freetgt(*t); 125 + if (d->bufpool) 126 + mempool_destroy(d->bufpool); 127 + kfree(d); 128 + } 129 + 130 + int 131 + aoedev_flush(const char __user *str, size_t cnt) 132 + { 133 + ulong flags; 134 + struct aoedev *d, **dd; 135 + struct aoedev *rmd = NULL; 136 + char buf[16]; 137 + int all = 0; 138 + 139 + if (cnt >= 3) { 140 + if (cnt > sizeof buf) 141 + cnt = sizeof buf; 142 + if (copy_from_user(buf, str, cnt)) 143 + return -EFAULT; 144 + all = !strncmp(buf, "all", 3); 145 + } 146 + 147 + flush_scheduled_work(); 148 + spin_lock_irqsave(&devlist_lock, flags); 149 + dd = &devlist; 150 + while ((d = *dd)) { 151 + spin_lock(&d->lock); 152 + if ((!all && (d->flags & DEVFL_UP)) 153 + || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 154 + || d->nopen) { 155 + spin_unlock(&d->lock); 156 + dd = &d->next; 157 + continue; 158 + } 159 + *dd = d->next; 160 + aoedev_downdev(d); 161 + d->flags |= DEVFL_TKILL; 162 + spin_unlock(&d->lock); 163 + d->next = rmd; 164 + rmd = d; 165 + } 166 + spin_unlock_irqrestore(&devlist_lock, flags); 167 + while ((d = rmd)) { 168 + rmd = d->next; 169 + del_timer_sync(&d->timer); 170 + aoedev_freedev(d); /* must be able to sleep */ 171 + } 172 + return 0; 173 + } 174 + 115 175 /* find it or malloc it */ 116 176 struct aoedev * 117 177 aoedev_by_sysminor_m(ulong sysminor) ··· 227 159 } 228 160 kfree(t->frames); 229 161 kfree(t); 230 - } 231 - 232 - static void 233 - aoedev_freedev(struct aoedev *d) 234 - { 235 - struct aoetgt **t, **e; 236 - 237 - if (d->gd) { 238 - aoedisk_rm_sysfs(d); 239 - del_gendisk(d->gd); 240 - put_disk(d->gd); 241 - } 242 - t = d->targets; 243 - e = t + NTARGETS; 244 - for (; t < e && *t; t++) 245 - freetgt(*t); 246 - if (d->bufpool) 247 - mempool_destroy(d->bufpool); 248 - kfree(d); 249 162 } 250 163 251 164 void