-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MetadataPath field to Mount struct #327
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -191,7 +191,8 @@ func addUncontainedSubtreesRecursive(dst map[string]bool, | |
// Then, we choose one of these trees which contains (exactly or via path | ||
// prefix) *all* mnt.Subtree. We then return the root of this tree. In both | ||
// the above examples, this algorithm returns the first Mount. | ||
func findMainMount(filesystemMounts []*Mount) *Mount { | ||
func findMainMount(filesystemMounts []*Mount, lookuppath string) *Mount { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand the purpose of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Here we want to make sure that if the command is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per my other comment, I think |
||
metadataPath := "" | ||
// Index this filesystem's mounts by path. Note: paths are unique here, | ||
// since non-last mounts were already excluded earlier. | ||
// | ||
|
@@ -240,6 +241,14 @@ func findMainMount(filesystemMounts []*Mount) *Mount { | |
uncontainedSubtrees := make(map[string]bool) | ||
addUncontainedSubtreesRecursive(uncontainedSubtrees, mntNode, allUncontainedSubtrees) | ||
if len(uncontainedSubtrees) != len(allUncontainedSubtrees) { | ||
if mnt.Subtree == "/"+baseDirName && !allSubtrees["/"] { | ||
metadataPath = mnt.Path | ||
} else if len(lookuppath) > 0 && | ||
(mainMount == nil || mainMount.ReadOnly || | ||
(strings.HasPrefix(lookuppath, mnt.Path) && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's tough to review this because the logic of this function is already pretty complex, in order to handle non-root subtrees. How about separating out looking for a
|
||
(len(lookuppath) == len(mnt.Path) || lookuppath[len(mnt.Path)] == '/'))) { | ||
mainMount = mnt | ||
} | ||
continue | ||
} | ||
// If there's more than one eligible mount, they should have the | ||
|
@@ -250,15 +259,25 @@ func findMainMount(filesystemMounts []*Mount) *Mount { | |
return nil | ||
} | ||
// Prefer a read-write mount to a read-only one. | ||
if mainMount == nil || mainMount.ReadOnly { | ||
if filepath.Base(mnt.Path) != baseDirName && | ||
(mainMount == nil || mainMount.ReadOnly || | ||
(len(lookuppath) > 0 && strings.HasPrefix(lookuppath, mnt.Path) && | ||
(len(lookuppath) == len(mnt.Path) || lookuppath[len(mnt.Path)] == '/'))) { | ||
mainMount = mnt | ||
} | ||
|
||
if filepath.Base(mnt.Path) == baseDirName { | ||
metadataPath = mnt.Path | ||
} | ||
} | ||
if mainMount != nil { | ||
mainMount.MetadataPath = metadataPath | ||
} | ||
return mainMount | ||
} | ||
|
||
// This is separate from loadMountInfo() only for unit testing. | ||
func readMountInfo(r io.Reader) error { | ||
func readMountInfo(r io.Reader, path string) error { | ||
mountsByPath := make(map[string]*Mount) | ||
mountsByDevice = make(map[DeviceNumber]*Mount) | ||
|
||
|
@@ -292,21 +311,21 @@ func readMountInfo(r io.Reader) error { | |
append(allMountsByDevice[mnt.DeviceNumber], mnt) | ||
} | ||
for deviceNumber, filesystemMounts := range allMountsByDevice { | ||
mountsByDevice[deviceNumber] = findMainMount(filesystemMounts) | ||
mountsByDevice[deviceNumber] = findMainMount(filesystemMounts, path) | ||
} | ||
return nil | ||
} | ||
|
||
// loadMountInfo populates the Mount mappings by parsing /proc/self/mountinfo. | ||
// It returns an error if the Mount mappings cannot be populated. | ||
func loadMountInfo() error { | ||
func loadMountInfo(path string) error { | ||
if !mountsInitialized { | ||
file, err := os.Open("/proc/self/mountinfo") | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
if err := readMountInfo(file); err != nil { | ||
if err := readMountInfo(file, path); err != nil { | ||
return err | ||
} | ||
mountsInitialized = true | ||
|
@@ -324,7 +343,7 @@ func filesystemLacksMainMountError(deviceNumber DeviceNumber) error { | |
func AllFilesystems() ([]*Mount, error) { | ||
mountMutex.Lock() | ||
defer mountMutex.Unlock() | ||
if err := loadMountInfo(); err != nil { | ||
if err := loadMountInfo(""); err != nil { | ||
return nil, err | ||
} | ||
|
||
|
@@ -345,7 +364,7 @@ func UpdateMountInfo() error { | |
mountMutex.Lock() | ||
defer mountMutex.Unlock() | ||
mountsInitialized = false | ||
return loadMountInfo() | ||
return loadMountInfo("") | ||
} | ||
|
||
// FindMount returns the main Mount object for the filesystem which contains the | ||
|
@@ -355,7 +374,7 @@ func UpdateMountInfo() error { | |
func FindMount(path string) (*Mount, error) { | ||
mountMutex.Lock() | ||
defer mountMutex.Unlock() | ||
if err := loadMountInfo(); err != nil { | ||
if err := loadMountInfo(path); err != nil { | ||
return nil, err | ||
} | ||
deviceNumber, err := getNumberOfContainingDevice(path) | ||
|
@@ -431,7 +450,7 @@ func getMountFromLink(link string) (*Mount, error) { | |
// Lookup mountpoints for device in global store | ||
mountMutex.Lock() | ||
defer mountMutex.Unlock() | ||
if err := loadMountInfo(); err != nil { | ||
if err := loadMountInfo(searchPath); err != nil { | ||
return nil, err | ||
} | ||
mnt, ok := mountsByDevice[deviceNumber] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be simpler to not have this field, and instead make
BaseDir()
appendbaseDirName
only ifSubtree
is not equal to"/" + baseDirName
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The need for this
MetadataPath
information associated with aMount struct
appeared during my testing. Without it, the chosen main mount would be the one that has aSubtree
equal to"/" + baseDirName
(if any). Problem is thePath
associated with thisMount
is used not only to locate fscrypt's metadata directory, but also to issueioctl
commands to lock or unlock for instance. So we could end up in a situation where a call tofscrypt unlock /home
leads to anioctl(FS_IOC_ADD_ENCRYPTION_KEY)
on/.fscrypt
. This is a problem in some circumstances; for instance I found myself not able to write to a file in a directory that I had previously unlocked.This is why this patch implements the idea you suggested earlier, but with an additional field to the
Mount struct
to keep separated the notion of metadata directory from the notion of mount path. IfMetadataPath
is not empty,BaseDir()
uses it to return the location of fscrypt's metadata directory, independently of the main mount path. IfMetadataPath
is empty, thenBaseDir()
proceeds with the main mountPath
andbaseDirName
(the usual case when.fscrypt
is not mounted directly).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that the desired behavior?
That will work fine, since the ioctl operates on the filesystem, not on any particular file. You have to pick some file or directory on the filesystem to execute it on. Usually the root directory is chosen, but it could be any file or directory on the filesystem and the effect will be the same.