Skip to content

Commit 4599649

Browse files
Al Virohubcapsc
authored andcommitted
orangefs: fix orangefs_superblock locking
* switch orangefs_remount() to taking ORANGEFS_SB(sb) instead of sb * remove from the list _before_ orangefs_unmount() - request_mutex in the latter will make sure that nothing observed in the loop in ORANGEFS_DEV_REMOUNT_ALL handling will get freed until the end of loop * on removal, keep the forward pointer and zero the back one. That way we can drop and regain the spinlock in the loop body (again, ORANGEFS_DEV_REMOUNT_ALL one) and still be able to get to the rest of the list. Signed-off-by: Al Viro <[email protected]> Signed-off-by: Mike Marshall <[email protected]>
1 parent 6d4c1a3 commit 4599649

File tree

3 files changed

+47
-58
lines changed

3 files changed

+47
-58
lines changed

fs/orangefs/devorangefs-req.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,7 @@ static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
572572
struct dev_mask_info_s mask_info = { 0 };
573573
struct dev_mask2_info_s mask2_info = { 0, 0 };
574574
int upstream_kmod = 1;
575-
struct list_head *tmp = NULL;
576-
struct orangefs_sb_info_s *orangefs_sb = NULL;
575+
struct orangefs_sb_info_s *orangefs_sb;
577576

578577
/* mtmoore: add locking here */
579578

@@ -619,26 +618,32 @@ static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
619618
gossip_debug(GOSSIP_DEV_DEBUG,
620619
"%s: priority remount in progress\n",
621620
__func__);
622-
list_for_each(tmp, &orangefs_superblocks) {
623-
orangefs_sb =
624-
list_entry(tmp,
625-
struct orangefs_sb_info_s,
626-
list);
627-
if (orangefs_sb && (orangefs_sb->sb)) {
621+
spin_lock(&orangefs_superblocks_lock);
622+
list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
623+
/*
624+
* We have to drop the spinlock, so entries can be
625+
* removed. They can't be freed, though, so we just
626+
* keep the forward pointers and zero the back ones -
627+
* that way we can get to the rest of the list.
628+
*/
629+
if (!orangefs_sb->list.prev)
630+
continue;
631+
gossip_debug(GOSSIP_DEV_DEBUG,
632+
"%s: Remounting SB %p\n",
633+
__func__,
634+
orangefs_sb);
635+
636+
spin_unlock(&orangefs_superblocks_lock);
637+
ret = orangefs_remount(orangefs_sb);
638+
spin_lock(&orangefs_superblocks_lock);
639+
if (ret) {
628640
gossip_debug(GOSSIP_DEV_DEBUG,
629-
"%s: Remounting SB %p\n",
630-
__func__,
641+
"SB %p remount failed\n",
631642
orangefs_sb);
632-
633-
ret = orangefs_remount(orangefs_sb->sb);
634-
if (ret) {
635-
gossip_debug(GOSSIP_DEV_DEBUG,
636-
"SB %p remount failed\n",
637-
orangefs_sb);
638-
break;
639-
}
643+
break;
640644
}
641645
}
646+
spin_unlock(&orangefs_superblocks_lock);
642647
gossip_debug(GOSSIP_DEV_DEBUG,
643648
"%s: priority remount complete\n",
644649
__func__);

fs/orangefs/orangefs-kernel.h

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
462462
void *data);
463463

464464
void orangefs_kill_sb(struct super_block *sb);
465-
int orangefs_remount(struct super_block *sb);
465+
int orangefs_remount(struct orangefs_sb_info_s *);
466466

467467
int fsid_key_table_initialize(void);
468468
void fsid_key_table_finalize(void);
@@ -598,38 +598,6 @@ int service_operation(struct orangefs_kernel_op_s *op,
598598
((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \
599599
ORANGEFS_OP_INTERRUPTIBLE : 0)
600600

601-
#define add_orangefs_sb(sb) \
602-
do { \
603-
gossip_debug(GOSSIP_SUPER_DEBUG, \
604-
"Adding SB %p to orangefs superblocks\n", \
605-
ORANGEFS_SB(sb)); \
606-
spin_lock(&orangefs_superblocks_lock); \
607-
list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); \
608-
spin_unlock(&orangefs_superblocks_lock); \
609-
} while (0)
610-
611-
#define remove_orangefs_sb(sb) \
612-
do { \
613-
struct list_head *tmp = NULL; \
614-
struct list_head *tmp_safe = NULL; \
615-
struct orangefs_sb_info_s *orangefs_sb = NULL; \
616-
\
617-
spin_lock(&orangefs_superblocks_lock); \
618-
list_for_each_safe(tmp, tmp_safe, &orangefs_superblocks) { \
619-
orangefs_sb = list_entry(tmp, \
620-
struct orangefs_sb_info_s, \
621-
list); \
622-
if (orangefs_sb && (orangefs_sb->sb == sb)) { \
623-
gossip_debug(GOSSIP_SUPER_DEBUG, \
624-
"Removing SB %p from orangefs superblocks\n", \
625-
orangefs_sb); \
626-
list_del(&orangefs_sb->list); \
627-
break; \
628-
} \
629-
} \
630-
spin_unlock(&orangefs_superblocks_lock); \
631-
} while (0)
632-
633601
#define fill_default_sys_attrs(sys_attr, type, mode) \
634602
do { \
635603
sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \

fs/orangefs/super.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
210210
* the client regains all of the mount information from us.
211211
* NOTE: this function assumes that the request_mutex is already acquired!
212212
*/
213-
int orangefs_remount(struct super_block *sb)
213+
int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
214214
{
215215
struct orangefs_kernel_op_s *new_op;
216216
int ret = -EINVAL;
@@ -221,7 +221,7 @@ int orangefs_remount(struct super_block *sb)
221221
if (!new_op)
222222
return -ENOMEM;
223223
strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
224-
ORANGEFS_SB(sb)->devname,
224+
orangefs_sb->devname,
225225
ORANGEFS_MAX_SERVER_ADDR_LEN);
226226

227227
gossip_debug(GOSSIP_SUPER_DEBUG,
@@ -244,8 +244,8 @@ int orangefs_remount(struct super_block *sb)
244244
* short-lived mapping that the system interface uses
245245
* to map this superblock to a particular mount entry
246246
*/
247-
ORANGEFS_SB(sb)->id = new_op->downcall.resp.fs_mount.id;
248-
ORANGEFS_SB(sb)->mount_pending = 0;
247+
orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
248+
orangefs_sb->mount_pending = 0;
249249
}
250250

251251
op_release(new_op);
@@ -485,7 +485,12 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
485485
* finally, add this sb to our list of known orangefs
486486
* sb's
487487
*/
488-
add_orangefs_sb(sb);
488+
gossip_debug(GOSSIP_SUPER_DEBUG,
489+
"Adding SB %p to orangefs superblocks\n",
490+
ORANGEFS_SB(sb));
491+
spin_lock(&orangefs_superblocks_lock);
492+
list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
493+
spin_unlock(&orangefs_superblocks_lock);
489494
op_release(new_op);
490495
return dget(sb->s_root);
491496

@@ -512,10 +517,21 @@ void orangefs_kill_sb(struct super_block *sb)
512517
* issue the unmount to userspace to tell it to remove the
513518
* dynamic mount info it has for this superblock
514519
*/
515-
orangefs_unmount_sb(sb);
520+
orangefs_unmount_sb(sb);
516521

517522
/* remove the sb from our list of orangefs specific sb's */
518-
remove_orangefs_sb(sb);
523+
524+
spin_lock(&orangefs_superblocks_lock);
525+
__list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */
526+
ORANGEFS_SB(sb)->list.prev = NULL;
527+
spin_unlock(&orangefs_superblocks_lock);
528+
529+
/*
530+
* make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
531+
* gets completed before we free the dang thing.
532+
*/
533+
mutex_lock(&request_mutex);
534+
mutex_unlock(&request_mutex);
519535

520536
/* free the orangefs superblock private data */
521537
kfree(ORANGEFS_SB(sb));

0 commit comments

Comments
 (0)