xref: /openbmc/linux/fs/notify/fdinfo.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2be77196bSCyrill Gorcunov #include <linux/file.h>
3be77196bSCyrill Gorcunov #include <linux/fs.h>
4be77196bSCyrill Gorcunov #include <linux/fsnotify_backend.h>
5be77196bSCyrill Gorcunov #include <linux/idr.h>
6be77196bSCyrill Gorcunov #include <linux/init.h>
7be77196bSCyrill Gorcunov #include <linux/inotify.h>
8be77196bSCyrill Gorcunov #include <linux/fanotify.h>
9be77196bSCyrill Gorcunov #include <linux/kernel.h>
10be77196bSCyrill Gorcunov #include <linux/namei.h>
11be77196bSCyrill Gorcunov #include <linux/sched.h>
12be77196bSCyrill Gorcunov #include <linux/types.h>
13be77196bSCyrill Gorcunov #include <linux/seq_file.h>
14be77196bSCyrill Gorcunov #include <linux/proc_fs.h>
15be77196bSCyrill Gorcunov #include <linux/exportfs.h>
16be77196bSCyrill Gorcunov 
17be77196bSCyrill Gorcunov #include "inotify/inotify.h"
18be77196bSCyrill Gorcunov #include "../fs/mount.h"
19be77196bSCyrill Gorcunov 
20be77196bSCyrill Gorcunov #if defined(CONFIG_PROC_FS)
21be77196bSCyrill Gorcunov 
22be77196bSCyrill Gorcunov #if defined(CONFIG_INOTIFY_USER) || defined(CONFIG_FANOTIFY)
23be77196bSCyrill Gorcunov 
24a3816ab0SJoe Perches static void show_fdinfo(struct seq_file *m, struct file *f,
25a3816ab0SJoe Perches 			void (*show)(struct seq_file *m,
26a3816ab0SJoe Perches 				     struct fsnotify_mark *mark))
27be77196bSCyrill Gorcunov {
28be77196bSCyrill Gorcunov 	struct fsnotify_group *group = f->private_data;
29be77196bSCyrill Gorcunov 	struct fsnotify_mark *mark;
30be77196bSCyrill Gorcunov 
3196680d2bSLinus Torvalds 	mutex_lock(&group->mark_mutex);
32be77196bSCyrill Gorcunov 	list_for_each_entry(mark, &group->marks_list, g_list) {
33a3816ab0SJoe Perches 		show(m, mark);
34a3816ab0SJoe Perches 		if (seq_has_overflowed(m))
35be77196bSCyrill Gorcunov 			break;
36be77196bSCyrill Gorcunov 	}
3796680d2bSLinus Torvalds 	mutex_unlock(&group->mark_mutex);
38be77196bSCyrill Gorcunov }
39be77196bSCyrill Gorcunov 
40be77196bSCyrill Gorcunov #if defined(CONFIG_EXPORTFS)
41a3816ab0SJoe Perches static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
42be77196bSCyrill Gorcunov {
43be77196bSCyrill Gorcunov 	struct {
44be77196bSCyrill Gorcunov 		struct file_handle handle;
451fc98d11SAndrey Vagin 		u8 pad[MAX_HANDLE_SZ];
46be77196bSCyrill Gorcunov 	} f;
47be77196bSCyrill Gorcunov 	int size, ret, i;
48be77196bSCyrill Gorcunov 
49be77196bSCyrill Gorcunov 	f.handle.handle_bytes = sizeof(f.pad);
50be77196bSCyrill Gorcunov 	size = f.handle.handle_bytes >> 2;
51be77196bSCyrill Gorcunov 
52be77196bSCyrill Gorcunov 	ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, 0);
537e882481SAndrey Vagin 	if ((ret == FILEID_INVALID) || (ret < 0)) {
54be77196bSCyrill Gorcunov 		WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret);
55a3816ab0SJoe Perches 		return;
56be77196bSCyrill Gorcunov 	}
57be77196bSCyrill Gorcunov 
58be77196bSCyrill Gorcunov 	f.handle.handle_type = ret;
59be77196bSCyrill Gorcunov 	f.handle.handle_bytes = size * sizeof(u32);
60be77196bSCyrill Gorcunov 
61a3816ab0SJoe Perches 	seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:",
62be77196bSCyrill Gorcunov 		   f.handle.handle_bytes, f.handle.handle_type);
63be77196bSCyrill Gorcunov 
64be77196bSCyrill Gorcunov 	for (i = 0; i < f.handle.handle_bytes; i++)
65a3816ab0SJoe Perches 		seq_printf(m, "%02x", (int)f.handle.f_handle[i]);
66be77196bSCyrill Gorcunov }
67be77196bSCyrill Gorcunov #else
68a3816ab0SJoe Perches static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
69be77196bSCyrill Gorcunov {
70be77196bSCyrill Gorcunov }
71be77196bSCyrill Gorcunov #endif
72be77196bSCyrill Gorcunov 
73be77196bSCyrill Gorcunov #ifdef CONFIG_INOTIFY_USER
74be77196bSCyrill Gorcunov 
75a3816ab0SJoe Perches static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
76be77196bSCyrill Gorcunov {
77be77196bSCyrill Gorcunov 	struct inotify_inode_mark *inode_mark;
78be77196bSCyrill Gorcunov 	struct inode *inode;
79be77196bSCyrill Gorcunov 
8086ffe245SJan Kara 	if (!(mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE))
81a3816ab0SJoe Perches 		return;
82be77196bSCyrill Gorcunov 
83be77196bSCyrill Gorcunov 	inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
8486ffe245SJan Kara 	inode = igrab(mark->connector->inode);
85be77196bSCyrill Gorcunov 	if (inode) {
8669335996SDave Hansen 		/*
8769335996SDave Hansen 		 * IN_ALL_EVENTS represents all of the mask bits
8869335996SDave Hansen 		 * that we expose to userspace.  There is at
8969335996SDave Hansen 		 * least one bit (FS_EVENT_ON_CHILD) which is
9069335996SDave Hansen 		 * used only internally to the kernel.
9169335996SDave Hansen 		 */
9269335996SDave Hansen 		u32 mask = mark->mask & IN_ALL_EVENTS;
93a3816ab0SJoe Perches 		seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ",
94a3816ab0SJoe Perches 			   inode_mark->wd, inode->i_ino, inode->i_sb->s_dev,
9569335996SDave Hansen 			   mask, mark->ignored_mask);
96a3816ab0SJoe Perches 		show_mark_fhandle(m, inode);
97a3816ab0SJoe Perches 		seq_putc(m, '\n');
98be77196bSCyrill Gorcunov 		iput(inode);
99be77196bSCyrill Gorcunov 	}
100be77196bSCyrill Gorcunov }
101be77196bSCyrill Gorcunov 
102a3816ab0SJoe Perches void inotify_show_fdinfo(struct seq_file *m, struct file *f)
103be77196bSCyrill Gorcunov {
104a3816ab0SJoe Perches 	show_fdinfo(m, f, inotify_fdinfo);
105be77196bSCyrill Gorcunov }
106be77196bSCyrill Gorcunov 
107be77196bSCyrill Gorcunov #endif /* CONFIG_INOTIFY_USER */
108be77196bSCyrill Gorcunov 
109be77196bSCyrill Gorcunov #ifdef CONFIG_FANOTIFY
110be77196bSCyrill Gorcunov 
111a3816ab0SJoe Perches static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
112be77196bSCyrill Gorcunov {
113e6dbcafbSCyrill Gorcunov 	unsigned int mflags = 0;
114be77196bSCyrill Gorcunov 	struct inode *inode;
115be77196bSCyrill Gorcunov 
116e6dbcafbSCyrill Gorcunov 	if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
117e6dbcafbSCyrill Gorcunov 		mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
118e6dbcafbSCyrill Gorcunov 
11986ffe245SJan Kara 	if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) {
12086ffe245SJan Kara 		inode = igrab(mark->connector->inode);
121be77196bSCyrill Gorcunov 		if (!inode)
122a3816ab0SJoe Perches 			return;
123a3816ab0SJoe Perches 		seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
124be77196bSCyrill Gorcunov 			   inode->i_ino, inode->i_sb->s_dev,
125e6dbcafbSCyrill Gorcunov 			   mflags, mark->mask, mark->ignored_mask);
126a3816ab0SJoe Perches 		show_mark_fhandle(m, inode);
127a3816ab0SJoe Perches 		seq_putc(m, '\n');
128be77196bSCyrill Gorcunov 		iput(inode);
12986ffe245SJan Kara 	} else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
13086ffe245SJan Kara 		struct mount *mnt = real_mount(mark->connector->mnt);
131be77196bSCyrill Gorcunov 
132a3816ab0SJoe Perches 		seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
133a3816ab0SJoe Perches 			   mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
134be77196bSCyrill Gorcunov 	}
135be77196bSCyrill Gorcunov }
136be77196bSCyrill Gorcunov 
137a3816ab0SJoe Perches void fanotify_show_fdinfo(struct seq_file *m, struct file *f)
138be77196bSCyrill Gorcunov {
139be77196bSCyrill Gorcunov 	struct fsnotify_group *group = f->private_data;
140be77196bSCyrill Gorcunov 	unsigned int flags = 0;
141be77196bSCyrill Gorcunov 
142be77196bSCyrill Gorcunov 	switch (group->priority) {
143be77196bSCyrill Gorcunov 	case FS_PRIO_0:
144be77196bSCyrill Gorcunov 		flags |= FAN_CLASS_NOTIF;
145be77196bSCyrill Gorcunov 		break;
146be77196bSCyrill Gorcunov 	case FS_PRIO_1:
147be77196bSCyrill Gorcunov 		flags |= FAN_CLASS_CONTENT;
148be77196bSCyrill Gorcunov 		break;
149be77196bSCyrill Gorcunov 	case FS_PRIO_2:
150be77196bSCyrill Gorcunov 		flags |= FAN_CLASS_PRE_CONTENT;
151be77196bSCyrill Gorcunov 		break;
152be77196bSCyrill Gorcunov 	}
153be77196bSCyrill Gorcunov 
154be77196bSCyrill Gorcunov 	if (group->max_events == UINT_MAX)
155be77196bSCyrill Gorcunov 		flags |= FAN_UNLIMITED_QUEUE;
156be77196bSCyrill Gorcunov 
157be77196bSCyrill Gorcunov 	if (group->fanotify_data.max_marks == UINT_MAX)
158be77196bSCyrill Gorcunov 		flags |= FAN_UNLIMITED_MARKS;
159be77196bSCyrill Gorcunov 
160be77196bSCyrill Gorcunov 	seq_printf(m, "fanotify flags:%x event-flags:%x\n",
161be77196bSCyrill Gorcunov 		   flags, group->fanotify_data.f_flags);
162be77196bSCyrill Gorcunov 
163a3816ab0SJoe Perches 	show_fdinfo(m, f, fanotify_fdinfo);
164be77196bSCyrill Gorcunov }
165be77196bSCyrill Gorcunov 
166be77196bSCyrill Gorcunov #endif /* CONFIG_FANOTIFY */
167be77196bSCyrill Gorcunov 
168be77196bSCyrill Gorcunov #endif /* CONFIG_INOTIFY_USER || CONFIG_FANOTIFY */
169be77196bSCyrill Gorcunov 
170be77196bSCyrill Gorcunov #endif /* CONFIG_PROC_FS */
171