diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 4a5863b79de9..fa053151fa96 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -421,6 +421,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; @@ -428,10 +438,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() @@ -596,6 +603,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 ac77d2be3c31..a67d1c682fed 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -142,9 +142,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); } @@ -197,6 +194,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, }; @@ -232,7 +234,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;