From: Jeff Mahoney <jeffm@suse.com>
Subject: vfs: add super_operations->get_inode_dev
References: bsc#927455 bsc#1176983
Patch-mainline: Never, Upstream submissions have been met with a request to use per-subvolume superblocks, which is unworkable in practice
There are many places where a dev_t:ino_t pair are passed to userspace
to uniquely describe an inode. Some file systems, like btrfs, have
multiple inode namespace internally and use a separate dev_t to make the
distinction between them.
This patch adds a super_operations->get_inode_dev operation to allow
the file system to export those dev_ts to callers within the kernel
for further export to userspace.
Without this patch, things like audit and some perf and trace events
will not distinguish between subvolumes within a single btrfs filesystem.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
arch/arc/kernel/troubleshoot.c | 2 +-
drivers/staging/lustre/lustre/llite/dir.c | 2 +-
drivers/staging/lustre/lustre/llite/file.c | 2 +-
fs/locks.c | 4 ++--
fs/nfsd/nfs3xdr.c | 2 +-
fs/nfsd/vfs.c | 6 +++---
fs/notify/fdinfo.c | 4 ++--
fs/proc/nommu.c | 2 +-
fs/proc/task_mmu.c | 2 +-
fs/proc/task_nommu.c | 2 +-
fs/proc_namespace.c | 3 ++-
fs/stat.c | 2 +-
include/linux/fs.h | 9 +++++++++
include/trace/events/filelock.h | 8 ++++----
include/trace/events/filemap.h | 2 +-
include/trace/events/writeback.h | 2 +-
kernel/audit.c | 2 +-
kernel/audit_fsnotify.c | 2 +-
kernel/audit_watch.c | 6 +++---
kernel/auditsc.c | 4 ++--
kernel/events/core.c | 2 +-
mm/memory-failure.c | 2 +-
net/unix/diag.c | 2 +-
security/tomoyo/condition.c | 2 +-
24 files changed, 43 insertions(+), 33 deletions(-)
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -104,7 +104,7 @@ static void show_faulting_vma(unsigned l
if (file) {
nm = file_path(file, buf, PAGE_SIZE - 1);
inode = file_inode(vma->vm_file);
- dev = inode->i_sb->s_dev;
+ dev = inode_get_dev(inode);
ino = inode->i_ino;
}
pr_info(" @off 0x%lx in [%s]\n"
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -1360,7 +1360,7 @@ skip_lmm:
struct lov_user_mds_data __user *lmdp;
lstat_t st = { 0 };
- st.st_dev = inode->i_sb->s_dev;
+ st.st_dev = inode_get_dev(inode);
st.st_mode = body->mbo_mode;
st.st_nlink = body->mbo_nlink;
st.st_uid = body->mbo_uid;
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -2964,7 +2964,7 @@ int ll_getattr(const struct path *path,
OBD_FAIL_TIMEOUT(OBD_FAIL_GETATTR_DELAY, 30);
- stat->dev = inode->i_sb->s_dev;
+ stat->dev = inode_get_dev(inode);
if (ll_need_32bit_api(sbi))
stat->ino = cl_fid_build_ino(&lli->lli_fid, 1);
else
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2682,8 +2682,8 @@ static void lock_get_status(struct seq_f
if (inode) {
/* userspace relies on this representation of dev_t */
seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
- MAJOR(inode->i_sb->s_dev),
- MINOR(inode->i_sb->s_dev), inode->i_ino);
+ MAJOR(inode_get_dev(inode)),
+ MINOR(inode_get_dev(inode)), inode->i_ino);
} else {
seq_printf(f, "%d <none>:0 ", fl_pid);
}
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -147,7 +147,7 @@ static __be32 *encode_fsid(__be32 *p, st
default:
case FSIDSOURCE_DEV:
p = xdr_encode_hyper(p, (u64)huge_encode_dev
- (fhp->fh_dentry->d_sb->s_dev));
+ (inode_get_dev(d_inode(fhp->fh_dentry))));
break;
case FSIDSOURCE_FSID:
p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -795,7 +795,7 @@ struct raparms *
nfsd_init_raparms(struct file *file)
{
struct inode *inode = file_inode(file);
- dev_t dev = inode->i_sb->s_dev;
+ dev_t dev = inode_get_dev(inode);
ino_t ino = inode->i_ino;
struct raparms *ra, **rap, **frap = NULL;
int depth = 0;
@@ -963,7 +963,7 @@ static int wait_for_concurrent_writes(st
int err = 0;
if (atomic_read(&inode->i_writecount) > 1
- || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) {
+ || (last_ino == inode->i_ino && last_dev == inode_get_dev(inode))) {
dprintk("nfsd: write defer %d\n", task_pid_nr(current));
msleep(10);
dprintk("nfsd: write resume %d\n", task_pid_nr(current));
@@ -974,7 +974,7 @@ static int wait_for_concurrent_writes(st
err = vfs_fsync(file, 0);
}
last_ino = inode->i_ino;
- last_dev = inode->i_sb->s_dev;
+ last_dev = inode_get_dev(inode);
return err;
}
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -90,7 +90,7 @@ static void inotify_fdinfo(struct seq_fi
*/
u32 mask = mark->mask & IN_ALL_EVENTS;
seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ",
- inode_mark->wd, inode->i_ino, inode->i_sb->s_dev,
+ inode_mark->wd, inode->i_ino, inode_get_dev(inode),
mask, mark->ignored_mask);
show_mark_fhandle(m, inode);
seq_putc(m, '\n');
@@ -120,7 +120,7 @@ static void fanotify_fdinfo(struct seq_f
if (!inode)
return;
seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
- inode->i_ino, inode->i_sb->s_dev,
+ inode->i_ino, inode_get_dev(inode),
mflags, mark->mask, mark->ignored_mask);
show_mark_fhandle(m, inode);
seq_putc(m, '\n');
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -46,7 +46,7 @@ static int nommu_region_show(struct seq_
if (file) {
struct inode *inode = file_inode(region->vm_file);
- dev = inode->i_sb->s_dev;
+ dev = inode_get_dev(inode);
ino = inode->i_ino;
}
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -295,7 +295,7 @@ show_map_vma(struct seq_file *m, struct
if (file) {
struct inode *inode = file_inode(vma->vm_file);
- dev = inode->i_sb->s_dev;
+ dev = inode_get_dev(inode);
ino = inode->i_ino;
pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
}
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -158,7 +158,7 @@ static int nommu_vma_show(struct seq_fil
if (file) {
struct inode *inode = file_inode(vma->vm_file);
- dev = inode->i_sb->s_dev;
+ dev = inode_get_dev(inode);
ino = inode->i_ino;
pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
}
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -133,10 +133,11 @@ static int show_mountinfo(struct seq_fil
struct mount *r = real_mount(mnt);
struct super_block *sb = mnt->mnt_sb;
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
+ dev_t dev = inode_get_dev(mnt->mnt_root->d_inode);
int err;
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
- MAJOR(sb->s_dev), MINOR(sb->s_dev));
+ MAJOR(dev), MINOR(dev));
if (sb->s_op->show_path) {
err = sb->s_op->show_path(m, mnt->mnt_root);
if (err)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -31,7 +31,7 @@
*/
void generic_fillattr(struct inode *inode, struct kstat *stat)
{
- stat->dev = inode->i_sb->s_dev;
+ stat->dev = inode_get_dev(inode);
stat->ino = inode->i_ino;
stat->mode = inode->i_mode;
stat->nlink = inode->i_nlink;
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1834,6 +1834,7 @@ struct super_operations {
struct shrink_control *);
long (*free_cached_objects)(struct super_block *,
struct shrink_control *);
+ dev_t (*get_inode_dev)(const struct inode *);
};
/*
@@ -3363,4 +3364,12 @@ static inline bool dir_relax_shared(stru
extern bool path_noexec(const struct path *path);
extern void inode_nohighmem(struct inode *inode);
+static inline dev_t inode_get_dev(const struct inode *inode)
+{
+ if (inode->i_sb->s_op->get_inode_dev)
+ return inode->i_sb->s_op->get_inode_dev(inode);
+
+ return inode->i_sb->s_dev;
+}
+
#endif /* _LINUX_FS_H */
--- a/include/trace/events/filelock.h
+++ b/include/trace/events/filelock.h
@@ -47,7 +47,7 @@ TRACE_EVENT(locks_get_lock_context,
),
TP_fast_assign(
- __entry->s_dev = inode->i_sb->s_dev;
+ __entry->s_dev = inode_get_dev(inode);
__entry->i_ino = inode->i_ino;
__entry->type = type;
__entry->ctx = ctx;
@@ -79,7 +79,7 @@ DECLARE_EVENT_CLASS(filelock_lock,
TP_fast_assign(
__entry->fl = fl ? fl : NULL;
- __entry->s_dev = inode->i_sb->s_dev;
+ __entry->s_dev = inode_get_dev(inode);
__entry->i_ino = inode->i_ino;
__entry->fl_next = fl ? fl->fl_next : NULL;
__entry->fl_owner = fl ? fl->fl_owner : NULL;
@@ -131,7 +131,7 @@ DECLARE_EVENT_CLASS(filelock_lease,
TP_fast_assign(
__entry->fl = fl ? fl : NULL;
- __entry->s_dev = inode->i_sb->s_dev;
+ __entry->s_dev = inode_get_dev(inode);
__entry->i_ino = inode->i_ino;
__entry->fl_next = fl ? fl->fl_next : NULL;
__entry->fl_owner = fl ? fl->fl_owner : NULL;
@@ -181,7 +181,7 @@ TRACE_EVENT(generic_add_lease,
),
TP_fast_assign(
- __entry->s_dev = inode->i_sb->s_dev;
+ __entry->s_dev = inode_get_dev(inode);
__entry->i_ino = inode->i_ino;
__entry->wcount = atomic_read(&inode->i_writecount);
__entry->dcount = d_count(fl->fl_file->f_path.dentry);
--- a/include/trace/events/filemap.h
+++ b/include/trace/events/filemap.h
@@ -30,7 +30,7 @@ DECLARE_EVENT_CLASS(mm_filemap_op_page_c
__entry->i_ino = page->mapping->host->i_ino;
__entry->index = page->index;
if (page->mapping->host->i_sb)
- __entry->s_dev = page->mapping->host->i_sb->s_dev;
+ __entry->s_dev = inode_get_dev(page->mapping->host);
else
__entry->s_dev = page->mapping->host->i_rdev;
),
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -708,7 +708,7 @@ DECLARE_EVENT_CLASS(writeback_inode_temp
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev = inode_get_dev(inode);
__entry->ino = inode->i_ino;
__entry->state = inode->i_state;
__entry->mode = inode->i_mode;
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2050,7 +2050,7 @@ void audit_copy_inode(struct audit_names
struct inode *inode)
{
name->ino = inode->i_ino;
- name->dev = inode->i_sb->s_dev;
+ name->dev = inode_get_dev(inode);
name->mode = inode->i_mode;
name->uid = inode->i_uid;
name->gid = inode->i_gid;
--- a/kernel/audit_fsnotify.c
+++ b/kernel/audit_fsnotify.c
@@ -76,7 +76,7 @@ int audit_mark_compare(struct audit_fsno
static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
const struct inode *inode)
{
- audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
+ audit_mark->dev = inode ? inode_get_dev(inode) : AUDIT_DEV_UNSET;
audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
}
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -368,7 +368,7 @@ static int audit_get_nd(struct audit_wat
inode_unlock(d_backing_inode(parent->dentry));
if (d_is_positive(d)) {
/* update watch filter fields */
- watch->dev = d->d_sb->s_dev;
+ watch->dev = inode_get_dev(d_backing_inode(d));
watch->ino = d_backing_inode(d)->i_ino;
}
dput(d);
@@ -509,7 +509,7 @@ static int audit_watch_handle_event(stru
}
if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
- audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
+ audit_update_watch(parent, dname, inode_get_dev(inode), inode->i_ino, 0);
else if (mask & (FS_DELETE|FS_MOVED_FROM))
audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
@@ -563,7 +563,7 @@ int audit_exe_compare(struct task_struct
if (!exe_file)
return 0;
ino = file_inode(exe_file)->i_ino;
- dev = file_inode(exe_file)->i_sb->s_dev;
+ dev = inode_get_dev(file_inode(exe_file));
fput(exe_file);
return audit_mark_compare(mark, ino, dev);
}
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1808,7 +1808,7 @@ void __audit_inode(struct filename *name
if (n->ino) {
/* valid inode number, use that for the comparison */
if (n->ino != inode->i_ino ||
- n->dev != inode->i_sb->s_dev)
+ n->dev != inode_get_dev(inode))
continue;
} else if (n->name) {
/* inode number has not been set, check the name */
@@ -1894,7 +1894,7 @@ void __audit_inode_child(struct inode *p
n->type != AUDIT_TYPE_UNKNOWN))
continue;
- if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
+ if (n->ino == parent->i_ino && n->dev == inode_get_dev(parent) &&
!audit_compare_dname_path(dname,
n->name->name, n->name_len)) {
if (n->type == AUDIT_TYPE_UNKNOWN)
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7169,7 +7169,7 @@ static void perf_event_mmap_event(struct
goto cpy_name;
}
inode = file_inode(vma->vm_file);
- dev = inode->i_sb->s_dev;
+ dev = inode_get_dev(inode);
ino = inode->i_ino;
gen = inode->i_generation;
maj = MAJOR(dev);
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -100,7 +100,7 @@ static int hwpoison_filter_dev(struct pa
if (mapping == NULL || mapping->host == NULL)
return -EINVAL;
- dev = mapping->host->i_sb->s_dev;
+ dev = inode_get_dev(mapping->host);
if (hwpoison_filter_dev_major != ~0U &&
hwpoison_filter_dev_major != MAJOR(dev))
return -EINVAL;
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -27,7 +27,7 @@ static int sk_diag_dump_vfs(struct sock
if (dentry) {
struct unix_diag_vfs uv = {
.udiag_vfs_ino = d_backing_inode(dentry)->i_ino,
- .udiag_vfs_dev = dentry->d_sb->s_dev,
+ .udiag_vfs_dev = inode_get_dev(d_backing_inode(dentry)),
};
return nla_put(nlskb, UNIX_DIAG_VFS, sizeof(uv), &uv);
--- a/security/tomoyo/condition.c
+++ b/security/tomoyo/condition.c
@@ -721,7 +721,7 @@ void tomoyo_get_attributes(struct tomoyo
stat->gid = inode->i_gid;
stat->ino = inode->i_ino;
stat->mode = inode->i_mode;
- stat->dev = inode->i_sb->s_dev;
+ stat->dev = inode_get_dev(inode);
stat->rdev = inode->i_rdev;
obj->stat_valid[i] = true;
}