Date: Sat, 22 Sep 2001 02:05:28 -0400 (EDT) From: Alexander Viro To: Linus Torvalds Cc: Andrea Arcangeli Subject: [PATCH] (3/6) further block_device cleanups In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Part 3: swapfile.c a) dead code removal. Not as much as I've expected, though. b) sys_swapon() does bd_acquire(). Corresponding bdput() added on failing exit. c) sys_swapoff() does bdput() (pair to bd_acquire() in swapon()). Both are in case of swap partitions, obviously. d) check for duplicates in swapon() (adding already activated swap component) had been unified - we simply compare ->swap_file->d_inode->i_mapping. Works both for files and for devices. e) failure recovery in swapon() fixed - we take swap_map out under swap_list_lock now and free it afterwards. Previously we vfree()'d it before taking the lock and left a dangling pointer for a while. And yes, it could lead to very unpleasant oopsen. diff -urN S10-pre13-get_sb_bdev/mm/swapfile.c S10-pre13-current/mm/swapfile.c --- S10-pre13-get_sb_bdev/mm/swapfile.c Fri Sep 21 09:45:30 2001 +++ S10-pre13-current/mm/swapfile.c Fri Sep 21 21:40:04 2001 @@ -567,14 +567,8 @@ for (type = swap_list.head; type >= 0; type = swap_info[type].next) { p = swap_info + type; if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { - if (p->swap_file) { - if (p->swap_file == nd.dentry) - break; - } else { - if (S_ISBLK(nd.dentry->d_inode->i_mode) - && (p->swap_device == nd.dentry->d_inode->i_rdev)) - break; - } + if (p->swap_file == nd.dentry) + break; } prev = type; } @@ -615,15 +609,17 @@ swap_list_unlock(); goto out_dput; } - if (p->swap_device) - blkdev_put(nd.dentry->d_inode->i_bdev, BDEV_SWAP); + if (p->swap_device) { + blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP); + bdput(p->swap_file->d_inode->i_bdev); + } path_release(&nd); swap_list_lock(); - nd.dentry = p->swap_file; - p->swap_file = NULL; nd.mnt = p->swap_vfsmnt; + nd.dentry = p->swap_file; p->swap_vfsmnt = NULL; + p->swap_file = NULL; p->swap_device = 0; p->max = 0; swap_map = p->swap_map; @@ -711,6 +707,7 @@ unsigned long maxpages = 1; int swapfilesize; struct block_device *bdev = NULL; + unsigned short *swap_map; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -760,41 +757,39 @@ p->swap_device = dev; set_blocksize(dev, PAGE_SIZE); + bd_acquire(swap_inode); bdev = swap_inode->i_bdev; bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode)); if (bdops) bdev->bd_op = bdops; error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP); - if (error) + if (error) { + bdput(bdev); goto bad_swap_2; + } set_blocksize(dev, PAGE_SIZE); error = -ENODEV; if (!dev || (blk_size[MAJOR(dev)] && !blk_size[MAJOR(dev)][MINOR(dev)])) goto bad_swap; - error = -EBUSY; - for (i = 0 ; i < nr_swapfiles ; i++) { - if (i == type) - continue; - if (dev == swap_info[i].swap_device) - goto bad_swap; - } swapfilesize = 0; if (blk_size[MAJOR(dev)]) swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] >> (PAGE_SHIFT - 10); - } else if (S_ISREG(swap_inode->i_mode)) { - error = -EBUSY; - for (i = 0 ; i < nr_swapfiles ; i++) { - if (i == type || !swap_info[i].swap_file) - continue; - if (swap_inode == swap_info[i].swap_file->d_inode) - goto bad_swap; - } + } else if (S_ISREG(swap_inode->i_mode)) swapfilesize = swap_inode->i_size >> PAGE_SHIFT; - } else + else goto bad_swap; + error = -EBUSY; + for (i = 0 ; i < nr_swapfiles ; i++) { + struct swap_info_struct *q = &swap_info[i]; + if (i == type || !q->swap_file) + continue; + if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping) + goto bad_swap; + } + swap_header = (void *) __get_free_page(GFP_USER); if (!swap_header) { printk("Unable to start swapping: out of memory :-)\n"); @@ -926,14 +921,15 @@ error = 0; goto out; bad_swap: - if (bdev) + if (bdev) { blkdev_put(bdev, BDEV_SWAP); + bdput(bdev); + } bad_swap_2: - if (p->swap_map) - vfree(p->swap_map); + swap_list_lock(); + swap_map = p->swap_map; nd.mnt = p->swap_vfsmnt; nd.dentry = p->swap_file; - swap_list_lock(); p->swap_device = 0; p->swap_file = NULL; p->swap_vfsmnt = NULL; @@ -942,6 +938,8 @@ if (!(swap_flags & SWAP_FLAG_PREFER)) ++least_priority; swap_list_unlock(); + if (swap_map) + vfree(swap_map); path_release(&nd); out: if (swap_header)