From patchwork Wed Jun 15 07:02:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: liubo X-Patchwork-Id: 12881870 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3F95DC43334 for ; Wed, 15 Jun 2022 07:02:40 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CEDCD6B0073; Wed, 15 Jun 2022 03:02:39 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id C9DAD6B0074; Wed, 15 Jun 2022 03:02:39 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B65A16B0075; Wed, 15 Jun 2022 03:02:39 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id A89F86B0073 for ; Wed, 15 Jun 2022 03:02:39 -0400 (EDT) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 7A24F795 for ; Wed, 15 Jun 2022 07:02:39 +0000 (UTC) X-FDA: 79579577238.03.DC4DF5A Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by imf16.hostedemail.com (Postfix) with ESMTP id 05067180075 for ; Wed, 15 Jun 2022 07:02:37 +0000 (UTC) Received: from dggemv711-chm.china.huawei.com (unknown [172.30.72.55]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4LNGPd4dyZzSgsZ; Wed, 15 Jun 2022 14:59:17 +0800 (CST) Received: from kwepemm600016.china.huawei.com (7.193.23.20) by dggemv711-chm.china.huawei.com (10.1.198.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 15 Jun 2022 15:02:16 +0800 Received: from huawei.com (10.175.124.27) by kwepemm600016.china.huawei.com (7.193.23.20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 15 Jun 2022 15:02:15 +0800 From: liubo To: , , CC: , , , , , , , , , , , Subject: [PATCH v2 1/2] mm/swapfile: Extract operations of resource release in the swapoff process Date: Wed, 15 Jun 2022 15:02:27 +0800 Message-ID: <20220615070228.2858170-2-liubo254@huawei.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20220615070228.2858170-1-liubo254@huawei.com> References: <20220615070228.2858170-1-liubo254@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.124.27] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To kwepemm600016.china.huawei.com (7.193.23.20) X-CFilter-Loop: Reflected ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1655276559; a=rsa-sha256; cv=none; b=MoQ2Qox2Cx80gipwzVRh0+B602W6CV4pjC/hZjnRINndL7lLIoEkKqPxMSINBUWhniM1zd TewtL7TXRm+8plyn3HfkwaKy2+bpM+mNNt/vN+qLfqNA2axQ6Zn7vo0yAA+m1zH7esPVuZ PRxVEmLvDokRSncLsCRx7f8Wj2R9I6w= ARC-Authentication-Results: i=1; imf16.hostedemail.com; dkim=none; spf=pass (imf16.hostedemail.com: domain of liubo254@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=liubo254@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1655276559; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BPT4DwNCtwGCq2rmgI1lIw631QmyxRlnRfoDWELL6ek=; b=Au4NqkWfnkYYjIeTEKtG3bC04siaIeVTPLA90uN4WVFhXdW9a+RTi/AqVqEECIoqLzvPXZ u/E3Y8mQiCe83umrgIZogjiMhXLKcjbv9Hy1z0a6YbkcdZN8yOaCZLaiF1snI8F6adjOV+ Z9vMG3t/AxUoe6NEkir34eRzjJwyrG0= X-Stat-Signature: 7hndrtdqdxktzia7dfcfypu8rwo9uoht X-Rspamd-Queue-Id: 05067180075 Authentication-Results: imf16.hostedemail.com; dkim=none; spf=pass (imf16.hostedemail.com: domain of liubo254@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=liubo254@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com X-Rspam-User: X-Rspamd-Server: rspam02 X-HE-Tag: 1655276557-576602 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: In order to realize the interface reuse in the swapoff resource release process, some of the operations are abstracted into separate interfaces. Only code movement, no functional modifications and changes. del_useless_swap_info(): Remove specific swap_info_struct from swap_active_head and update total_swap_pages. release_swap_info_memory(): Clear the corresponding resources of swap_info_struct. Signed-off-by: liubo --- v2: Only code movement, no functional modifications and changes. Former: https://lore.kernel.org/linux-mm/20220528084941.28391-1-liubo254@huawei.com/ --- mm/swapfile.c | 168 +++++++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 3fa26f6971e9..2ef5e7b4918e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2386,18 +2386,103 @@ bool has_usable_swap(void) return ret; } -SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) +static void release_swap_info_memory(struct swap_info_struct *p) { - struct swap_info_struct *p = NULL; unsigned char *swap_map; struct swap_cluster_info *cluster_info; unsigned long *frontswap_map; - struct file *swap_file, *victim; + struct file *swap_file; struct address_space *mapping; struct inode *inode; + unsigned int old_block_size; + + mutex_lock(&swapon_mutex); + spin_lock(&swap_lock); + spin_lock(&p->lock); + drain_mmlist(); + + /* wait for anyone still in scan_swap_map */ + p->highest_bit = 0; /* cuts scans short */ + while (p->flags >= SWP_SCANNING) { + spin_unlock(&p->lock); + spin_unlock(&swap_lock); + schedule_timeout_uninterruptible(1); + spin_lock(&swap_lock); + spin_lock(&p->lock); + } + + swap_file = p->swap_file; + mapping = p->swap_file->f_mapping; + old_block_size = p->old_block_size; + p->swap_file = NULL; + p->max = 0; + swap_map = p->swap_map; + p->swap_map = NULL; + cluster_info = p->cluster_info; + p->cluster_info = NULL; + frontswap_map = frontswap_map_get(p); + spin_unlock(&p->lock); + spin_unlock(&swap_lock); + arch_swap_invalidate_area(p->type); + frontswap_invalidate_area(p->type); + frontswap_map_set(p, NULL); + mutex_unlock(&swapon_mutex); + free_percpu(p->percpu_cluster); + p->percpu_cluster = NULL; + free_percpu(p->cluster_next_cpu); + p->cluster_next_cpu = NULL; + vfree(swap_map); + kvfree(cluster_info); + kvfree(frontswap_map); + /* Destroy swap account information */ + swap_cgroup_swapoff(p->type); + exit_swap_address_space(p->type); + + inode = mapping->host; + if (S_ISBLK(inode->i_mode)) { + struct block_device *bdev = I_BDEV(inode); + + set_blocksize(bdev, old_block_size); + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + } + + inode_lock(inode); + inode->i_flags &= ~S_SWAPFILE; + inode_unlock(inode); + filp_close(swap_file, NULL); +} + +static void del_useless_swap_info(struct swap_info_struct *p) +{ + del_from_avail_list(p); + spin_lock(&p->lock); + if (p->prio < 0) { + struct swap_info_struct *si = p; + int nid; + + plist_for_each_entry_continue(si, &swap_active_head, list) { + si->prio++; + si->list.prio--; + for_each_node(nid) { + if (si->avail_lists[nid].prio != 1) + si->avail_lists[nid].prio--; + } + } + least_priority++; + } + plist_del(&p->list, &swap_active_head); + atomic_long_sub(p->pages, &nr_swap_pages); + p->flags &= ~SWP_WRITEOK; + spin_unlock(&p->lock); +} + +SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) +{ + struct swap_info_struct *p = NULL; + struct file *victim; + struct address_space *mapping; struct filename *pathname; int err, found = 0; - unsigned int old_block_size; unsigned int inuse_pages; if (!capable(CAP_SYS_ADMIN)) @@ -2440,26 +2525,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); goto out_dput; } - del_from_avail_list(p); - spin_lock(&p->lock); - if (p->prio < 0) { - struct swap_info_struct *si = p; - int nid; - plist_for_each_entry_continue(si, &swap_active_head, list) { - si->prio++; - si->list.prio--; - for_each_node(nid) { - if (si->avail_lists[nid].prio != 1) - si->avail_lists[nid].prio--; - } - } - least_priority++; - } - plist_del(&p->list, &swap_active_head); - atomic_long_sub(p->pages, &nr_swap_pages); - p->flags &= ~SWP_WRITEOK; - spin_unlock(&p->lock); + del_useless_swap_info(p); spin_unlock(&swap_lock); disable_swap_slots_cache_lock(); @@ -2497,60 +2564,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (!p->bdev || !bdev_nonrot(p->bdev)) atomic_dec(&nr_rotate_swap); - mutex_lock(&swapon_mutex); - spin_lock(&swap_lock); - spin_lock(&p->lock); - drain_mmlist(); - - /* wait for anyone still in scan_swap_map_slots */ - p->highest_bit = 0; /* cuts scans short */ - while (p->flags >= SWP_SCANNING) { - spin_unlock(&p->lock); - spin_unlock(&swap_lock); - schedule_timeout_uninterruptible(1); - spin_lock(&swap_lock); - spin_lock(&p->lock); - } - - swap_file = p->swap_file; - old_block_size = p->old_block_size; - p->swap_file = NULL; - p->max = 0; - swap_map = p->swap_map; - p->swap_map = NULL; - cluster_info = p->cluster_info; - p->cluster_info = NULL; - frontswap_map = frontswap_map_get(p); - spin_unlock(&p->lock); - spin_unlock(&swap_lock); - arch_swap_invalidate_area(p->type); - frontswap_invalidate_area(p->type); - frontswap_map_set(p, NULL); - mutex_unlock(&swapon_mutex); - free_percpu(p->percpu_cluster); - p->percpu_cluster = NULL; - free_percpu(p->cluster_next_cpu); - p->cluster_next_cpu = NULL; - vfree(swap_map); - kvfree(cluster_info); - kvfree(frontswap_map); - /* Destroy swap account information */ - swap_cgroup_swapoff(p->type); - exit_swap_address_space(p->type); - - inode = mapping->host; - if (S_ISBLK(inode->i_mode)) { - struct block_device *bdev = I_BDEV(inode); - - set_blocksize(bdev, old_block_size); - blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); - } - - inode_lock(inode); - inode->i_flags &= ~S_SWAPFILE; - inode_unlock(inode); - filp_close(swap_file, NULL); - + release_swap_info_memory(p); /* * Clear the SWP_USED flag after all resources are freed so that swapon * can reuse this swap_info in alloc_swap_info() safely. It is ok to From patchwork Wed Jun 15 07:02:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: liubo X-Patchwork-Id: 12881869 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 52459C43334 for ; Wed, 15 Jun 2022 07:02:35 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id E27216B0072; Wed, 15 Jun 2022 03:02:34 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id DD66D6B0073; Wed, 15 Jun 2022 03:02:34 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C9DFC6B0074; Wed, 15 Jun 2022 03:02:34 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id BB9EF6B0072 for ; Wed, 15 Jun 2022 03:02:34 -0400 (EDT) Received: from smtpin13.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay11.hostedemail.com (Postfix) with ESMTP id 8B23E80AC6 for ; Wed, 15 Jun 2022 07:02:34 +0000 (UTC) X-FDA: 79579577028.13.01BA031 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by imf27.hostedemail.com (Postfix) with ESMTP id 9E43440011 for ; Wed, 15 Jun 2022 07:02:28 +0000 (UTC) Received: from dggemv704-chm.china.huawei.com (unknown [172.30.72.54]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4LNGPM6tFQzSgrL; Wed, 15 Jun 2022 14:59:03 +0800 (CST) Received: from kwepemm600016.china.huawei.com (7.193.23.20) by dggemv704-chm.china.huawei.com (10.3.19.47) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 15 Jun 2022 15:02:17 +0800 Received: from huawei.com (10.175.124.27) by kwepemm600016.china.huawei.com (7.193.23.20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 15 Jun 2022 15:02:16 +0800 From: liubo To: , , CC: , , , , , , , , , , , Subject: [PATCH v2 2/2] mm/swapfile: release swap info when swap device is unpluged Date: Wed, 15 Jun 2022 15:02:28 +0800 Message-ID: <20220615070228.2858170-3-liubo254@huawei.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20220615070228.2858170-1-liubo254@huawei.com> References: <20220615070228.2858170-1-liubo254@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.124.27] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To kwepemm600016.china.huawei.com (7.193.23.20) X-CFilter-Loop: Reflected ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1655276549; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eRK1dXC7RMaCDPNx+7jHrP6ogbkYZhMQu2j1w8Tl+YQ=; b=G9D98FiSSOA+55DTO2Ow11wPSagsvi30dWdusQmRSDQFU659HNrW5wed/ir/nrTyh4Q/pd pR4OncWv2pisFnvAfx+NLbOztfOfKeYNQIhR2d5+stkpIBzBqHyS7S2buZQdNI2Hm66iSe eP0i68Hv1kWVnhFK4PFkWmsgRUrfgKE= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf27.hostedemail.com: domain of liubo254@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=liubo254@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1655276549; a=rsa-sha256; cv=none; b=yAdc3THcBFOCjMtfDz4wG4l+jr8Mmge4IBjhyvn8J3XjdrfxEhxgY3JSVccBqxKd88cDa7 vXvZ8NHSRYGiowqlthIUSAYLPz/twldkzq9hQLehHQizchhZ31QSagYViwIQgeVmBT+sWz DC5QpPN53+5ZwreaCxCTqHgR74My6g0= X-Rspamd-Queue-Id: 9E43440011 X-Rspam-User: X-Stat-Signature: 133c9qt4o3tfrxr5895mp8f6w3ksodrp Authentication-Results: imf27.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf27.hostedemail.com: domain of liubo254@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=liubo254@huawei.com X-Rspamd-Server: rspam04 X-HE-Tag: 1655276548-400458 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: When the swap partition is mounted through the swapon command, the kernel will create the swap_info_struct data structure and initialize it, and save it in the swap_info global array. When the swap partition is no longer in use, the disk is unloaded through the swapoff command. However, if the disk is pulled out after swapon, an error will occur when swapoff the disk, causing the swap_info_struct data structure to remain in the kernel and cannot be cleared. This patch identifies which disks are no longer available by adding a traversal operation for swap_active_head available swap partitions in the swapon and swapoff processes, so as to clear the above data structures and release the corresponding resources. Example: [root@localhost ~]# swapon -s [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.1T 0 disk ├─sda1 8:1 0 600M 0 part /boot/efi ├─sda2 8:2 0 1G 0 part /boot └─sda3 8:3 0 1.1T 0 part ├─root 253:0 0 70G 0 lvm / ├─swap 253:1 0 4G 0 lvm └─home 253:2 0 1T 0 lvm /home nvme0n1 259:0 0 3.6T 0 disk └─nvme0n1p1 259:5 0 60G 0 part [root@localhost ~]# swapon /dev/nvme0n1p1 [root@localhost ~]# swapon -s Filename Type Size Used Priority /dev/nvme0n1p1 partition 62914556 0 -2 [root@localhost ~]# echo 1 > /sys/bus/pci/devices/0000:d8:00.0/remove [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.1T 0 disk ├─sda1 8:1 0 600M 0 part /boot/efi ├─sda2 8:2 0 1G 0 part /boot └─sda3 8:3 0 1.1T 0 part ├─root 253:0 0 70G 0 lvm / ├─swap 253:1 0 4G 0 lvm └─home 253:2 0 1T 0 lvm /home [root@localhost ~]# swapon -s Filename Type Size Used Priority /dev/nvme0n1p1 partition 62914556 0 -2 [root@localhost ~]# swapoff /dev/nvme0n1p1 swapoff: /dev/nvme0n1p1: swapoff failed: No such file or directory [root@localhost ~]# swapoff -a [root@localhost ~]# swapon -s Filename Type Size Used Priority /dev/nvme0n1p1 partition 62914556 0 -2 In the swapoff command, the device is acquired in the following ways, but the device has been unplugged at this time, causing the "victim" acquisition to fail, thus returning an error directly. And the invalid swap_info_struct cannot be effectively released. pathname = getname(specialfile); if (IS_ERR(pathname)) return PTR_ERR(pathname); victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) goto out; In order to solve the above problems, by adding traversal of swap_avail_heads (available swap partitions) in the swapoff and swapon processes, find the swap_info_struct whose disk partition has been unplugged, and release resources. The reason why the judgment of unavailable swap information is also added to the swapon process is that the swapoff is executed by the user, and the timing is uncontrollable. The system supports swapon multiple disks, and the unavailable swap can be deleted at the same time as swapon is mounted. Signed-off-by: liubo --- v2: The possible solution to the problem that the swap resources are not released when the swap partition is hot-pluged. The actual fix of the former patch. Former:https://lore.kernel.org/linux-mm/20220528084941.28391-1-liubo254@huawei.com/ --- mm/swapfile.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 2ef5e7b4918e..91208de9f689 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -68,6 +68,7 @@ static const char Bad_file[] = "Bad swap file entry "; static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; static const char Unused_offset[] = "Unused swap offset entry "; +static const char invalid_info[] = "deleted"; /* * all active swap_info_structs @@ -2476,6 +2477,88 @@ static void del_useless_swap_info(struct swap_info_struct *p) spin_unlock(&p->lock); } +static int swapoff_invalid_swapinfo(void) +{ + struct swap_info_struct *p = NULL; + struct file *swap_file; + int err, found = 0; + + char *tmp = NULL; + char *swap_name = NULL; + + tmp = kvzalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp) + return -ENOMEM; +rescan: + memset(tmp, 0, PAGE_SIZE); + spin_lock(&swap_lock); + plist_for_each_entry(p, &swap_active_head, list) { + if (p->flags & SWP_WRITEOK) { + swap_file = p->swap_file; + swap_name = d_path(&swap_file->f_path, tmp, PAGE_SIZE); + + if (strstr(swap_name, invalid_info)) { + found = 1; + break; + } + } + } + + if (!found) { + err = 0; + spin_unlock(&swap_lock); + goto out; + } + + total_swap_pages -= p->pages; + + del_useless_swap_info(p); + spin_unlock(&swap_lock); + + disable_swap_slots_cache_lock(); + set_current_oom_origin(); + try_to_unuse(p->type); + clear_current_oom_origin(); + + reenable_swap_slots_cache_unlock(); + + /* + * wait for swap operations protected by get/put_swap_device() + * to complete + */ + synchronize_rcu(); + + flush_work(&p->discard_work); + + destroy_swap_extents(p); + if (p->flags & SWP_CONTINUED) + free_swap_count_continuations(p); + + if (!p->bdev || !blk_queue_nonrot(bdev_get_queue(p->bdev))) + atomic_dec(&nr_rotate_swap); + + release_swap_info_memory(p); + + /* + * Clear the SWP_USED flag after all resources are freed so that swapon + * can reuse this swap_info in alloc_swap_info() safely. It is ok to + * not hold p->lock after we cleared its SWP_WRITEOK. + */ + spin_lock(&swap_lock); + p->flags = 0; + spin_unlock(&swap_lock); + + err = 0; + atomic_inc(&proc_poll_event); + wake_up_interruptible(&proc_poll_wait); + + found = 0; + goto rescan; +out: + kfree(tmp); + return err; +} + SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) { struct swap_info_struct *p = NULL; @@ -2496,8 +2579,12 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); - if (IS_ERR(victim)) + if (IS_ERR(victim)) { + /* check if the pathname is a device that has been unpluged */ + err = swapoff_invalid_swapinfo(); + err = err < 0 ? err : PTR_ERR(victim); goto out; + } mapping = victim->f_mapping; spin_lock(&swap_lock); @@ -3028,6 +3115,10 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (!swap_avail_heads) return -ENOMEM; + error = swapoff_invalid_swapinfo(); + if (error < 0) + return error; + p = alloc_swap_info(); if (IS_ERR(p)) return PTR_ERR(p);