summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--trans/fakeroot.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/trans/fakeroot.c b/trans/fakeroot.c
index 0eb514a9..3592d720 100644
--- a/trans/fakeroot.c
+++ b/trans/fakeroot.c
@@ -324,23 +324,32 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir,
char *name, struct node **np)
{
error_t err;
- int flags = O_RDWR|O_EXEC;
- file_t file = file_name_lookup_under (dir->nn->file, name,
- flags | O_NOLINK, 0);
+ int flags;
+ const file_t dirfile = dir->nn->file;
+ file_t file;
+
+ /* We must unlock the directory before making RPCs to the underlying
+ filesystem in case they somehow wind up trying to refer back to one of
+ our nodes. The DIRFILE port will not change or die as long as DIR
+ lives, and our caller holds a reference keeping it alive. */
+ mutex_unlock (&dir->lock);
+
+ flags = O_RDWR|O_EXEC;
+ file = file_name_lookup_under (dirfile, name, flags | O_NOLINK, 0);
if (file == MACH_PORT_NULL && errno == EACCES)
{
flags = O_RDWR;
- file = file_name_lookup_under (dir->nn->file, name, flags | O_NOLINK, 0);
+ file = file_name_lookup_under (dirfile, name, flags | O_NOLINK, 0);
}
if (file == MACH_PORT_NULL && errno == EACCES)
{
flags = O_READ|O_EXEC;
- file = file_name_lookup_under (dir->nn->file, name, flags | O_NOLINK, 0);
+ file = file_name_lookup_under (dirfile, name, flags | O_NOLINK, 0);
}
if (file == MACH_PORT_NULL && errno == EACCES)
{
flags = O_READ;
- file = file_name_lookup_under (dir->nn->file, name, flags | O_NOLINK, 0);
+ file = file_name_lookup_under (dirfile, name, flags | O_NOLINK, 0);
}
*np = 0;
if (file == MACH_PORT_NULL)
@@ -372,7 +381,7 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir,
}
}
}
- mutex_unlock (&dir->lock);
+
if (*np)
mutex_lock (&(*np)->lock);
return err;