diff options
author | Sergey Bugaev <bugaevc@gmail.com> | 2021-05-21 12:56:19 +0300 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2022-08-10 22:03:52 +0200 |
commit | b15326a788615988df10d4f2dbe39190126135d6 (patch) | |
tree | de9cad065774b8a0fb21f66e77a19237d1f70d19 /fatfs | |
parent | 88ee4ae44bd64e869bca79d0a6c6e6d4577b7170 (diff) | |
download | hurd-b15326a788615988df10d4f2dbe39190126135d6.tar.gz hurd-b15326a788615988df10d4f2dbe39190126135d6.tar.bz2 hurd-b15326a788615988df10d4f2dbe39190126135d6.zip |
fatfs: Properly reference pager
A node keeps a weak reference on the pager as long as
diskfs_node_disknode (node)->pager points to it. A pager keeps a light
reference on the node as long as the UPI is alive.
This is the same way it's done in ext2fs.
Diffstat (limited to 'fatfs')
-rw-r--r-- | fatfs/pager.c | 97 |
1 files changed, 49 insertions, 48 deletions
diff --git a/fatfs/pager.c b/fatfs/pager.c index 53b5bbc1..c1da666f 100644 --- a/fatfs/pager.c +++ b/fatfs/pager.c @@ -736,17 +736,7 @@ void pager_clear_user_data (struct user_pager_info *upi) { if (upi->type == FILE_DATA) - { - struct pager *pager; - - pthread_spin_lock (&node_to_page_lock); - pager = upi->node->dn->pager; - if (pager && pager_get_upi (pager) == upi) - upi->node->dn->pager = 0; - pthread_spin_unlock (&node_to_page_lock); - - diskfs_nrele_light (upi->node); - } + diskfs_nrele_light (upi->node); } /* This will be called when the ports library wants to drop weak @@ -754,8 +744,25 @@ pager_clear_user_data (struct user_pager_info *upi) If the user doesn't either, then it's OK for this function to do nothing. */ void -pager_dropweak (struct user_pager_info *p __attribute__ ((unused))) +pager_dropweak (struct user_pager_info *upi) { + struct pager *pager; + + if (upi->type != FILE_DATA) + return; + + pthread_spin_lock (&node_to_page_lock); + + pager = diskfs_node_disknode (upi->node)->pager; + + if (pager) + { + assert_backtrace (pager_get_upi (pager) == upi); + diskfs_node_disknode (upi->node)->pager = NULL; + ports_port_deref_weak (pager); + } + + pthread_spin_unlock (&node_to_page_lock); } /* Create the disk pager. */ @@ -813,51 +820,45 @@ resume_fat_pager (void) mach_port_t diskfs_get_filemap (struct node *node, vm_prot_t prot) { + struct pager *pager; mach_port_t right; - + assert_backtrace (S_ISDIR (node->dn_stat.st_mode) || S_ISREG (node->dn_stat.st_mode) || (S_ISLNK (node->dn_stat.st_mode))); - + pthread_spin_lock (&node_to_page_lock); - do + + pager = diskfs_node_disknode (node)->pager; + if (pager) { - struct pager *pager = node->dn->pager; - if (pager) - { - /* Because PAGER is not a real reference, this might be - nearly deallocated. If that's so, then the port right - will be null. In that case, clear here and loop. The - deallocation will complete separately. */ - right = pager_get_port (pager); - if (right == MACH_PORT_NULL) - node->dn->pager = 0; - else - pager_get_upi (pager)->max_prot |= prot; - } - else + right = pager_get_port (pager); + pager_get_upi (pager)->max_prot |= prot; + } + else + { + struct user_pager_info *upi; + pager = pager_create_alloc (sizeof *upi, file_pager_bucket, + MAY_CACHE, MEMORY_OBJECT_COPY_DELAY, 0); + if (pager == NULL) { - struct user_pager_info *upi; - node->dn->pager = - pager_create_alloc (sizeof *upi, file_pager_bucket, MAY_CACHE, - MEMORY_OBJECT_COPY_DELAY, 0); - if (node->dn->pager == NULL) - { - diskfs_nrele_light (node); - pthread_spin_unlock (&node_to_page_lock); - return MACH_PORT_NULL; - } - upi = pager_get_upi (node->dn->pager); - upi->type = FILE_DATA; - upi->node = node; - upi->max_prot = prot; - diskfs_nref_light (node); - - right = pager_get_port (node->dn->pager); - ports_port_deref (node->dn->pager); + pthread_spin_unlock (&node_to_page_lock); + return MACH_PORT_NULL; } + upi = pager_get_upi (pager); + upi->type = FILE_DATA; + upi->node = node; + upi->max_prot = prot; + diskfs_nref_light (node); + diskfs_node_disknode (node)->pager = pager; + + /* A weak reference for being part of the node. */ + ports_port_ref_weak (pager); + + right = pager_get_port (pager); + ports_port_deref (pager); } - while (right == MACH_PORT_NULL); + pthread_spin_unlock (&node_to_page_lock); mach_port_insert_right (mach_task_self (), right, right, |