summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/kernfs/file.c18
-rw-r--r--fs/sysfs/file.c12
2 files changed, 22 insertions, 8 deletions
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 990c97fa704..1e3cae64d2d 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -422,6 +422,16 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma)
const struct kernfs_ops *ops;
int rc;
+ /*
+ * mmap path and of->mutex are prone to triggering spurious lockdep
+ * warnings and we don't want to add spurious locking dependency
+ * between the two. Check whether mmap is actually implemented
+ * without grabbing @of->mutex by testing HAS_MMAP flag. See the
+ * comment in kernfs_file_open() for more details.
+ */
+ if (!(of->sd->s_flags & SYSFS_FLAG_HAS_MMAP))
+ return -ENODEV;
+
mutex_lock(&of->mutex);
rc = -ENODEV;
@@ -429,10 +439,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma)
goto out_unlock;
ops = kernfs_ops(of->sd);
- if (ops->mmap)
- rc = ops->mmap(of, vma);
- if (rc)
- goto out_put;
+ rc = ops->mmap(of, vma);
/*
* PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup()
@@ -597,6 +604,9 @@ static int kernfs_file_open(struct inode *inode, struct file *file)
* happen on the same file. At this point, we can't easily give
* each file a separate locking class. Let's differentiate on
* whether the file has mmap or not for now.
+ *
+ * Both paths of the branch look the same. They're supposed to
+ * look that way and give @of->mutex different static lockdep keys.
*/
if (has_mmap)
mutex_init(&of->mutex);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5da8bd1d04e..a7a188c3ed5 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -143,9 +143,6 @@ static int sysfs_kf_bin_mmap(struct sysfs_open_file *of,
struct bin_attribute *battr = of->sd->priv;
struct kobject *kobj = of->sd->s_parent->priv;
- if (!battr->mmap)
- return -ENODEV;
-
return battr->mmap(of->file, kobj, battr, vma);
}
@@ -198,6 +195,11 @@ static const struct kernfs_ops sysfs_bin_kfops_wo = {
static const struct kernfs_ops sysfs_bin_kfops_rw = {
.read = sysfs_kf_bin_read,
.write = sysfs_kf_bin_write,
+};
+
+static const struct kernfs_ops sysfs_bin_kfops_mmap = {
+ .read = sysfs_kf_bin_read,
+ .write = sysfs_kf_bin_write,
.mmap = sysfs_kf_bin_mmap,
};
@@ -233,7 +235,9 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
} else {
struct bin_attribute *battr = (void *)attr;
- if ((battr->read && battr->write) || battr->mmap)
+ if (battr->mmap)
+ ops = &sysfs_bin_kfops_mmap;
+ else if (battr->read && battr->write)
ops = &sysfs_bin_kfops_rw;
else if (battr->read)
ops = &sysfs_bin_kfops_ro;