Skip to content

Commit 4f7e333

Browse files
committed
fs: Enhanced read-only filesystem error notification mechanism
The error notification mechanism has been rewritten: instead of sending netlink messages directly from the fs module, it now uses a Blocking Notifier Chain within the overlayfs module, enabling external modules to send netlink messages later. Key changes: - Replaced `deepin_should_notify_error` with `deepin_notify_error` in `super_operations`. - Added handling for the two paths that need to be reported in the rename system call. - Added a new macro `deepin_should_notify_ro_fs_err` to simplify error-checking code. Link: deepin-community#1268 Signed-off-by: electricface <[email protected]>
1 parent 935caa3 commit 4f7e333

File tree

12 files changed

+356
-227
lines changed

12 files changed

+356
-227
lines changed

fs/deepin_err_notify.c

Lines changed: 78 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,194 +1,133 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* fs/deepin_ro_fs_err_notify.c - Deepin read-only filesystem error notification
3+
* Deepin filesystem error notification
44
*
5-
* This module provides notification functionality for read-only filesystem
6-
* errors, specifically targeting overlay filesystems mounted on /usr.
5+
* This module provides notification functionality for filesystem errors,
6+
* especially for read-only filesystem errors.
77
*/
88

99
#include <linux/init.h>
1010
#include <linux/slab.h>
1111
#include <linux/fs.h>
12-
#include <linux/namei.h>
13-
#include <linux/mount.h>
1412
#include <linux/path.h>
1513
#include <linux/dcache.h>
16-
#include <linux/sched.h>
1714
#include <linux/printk.h>
18-
#include <linux/string.h>
1915
#include <linux/err.h>
20-
#include <linux/limits.h>
2116
#include <linux/sysctl.h>
22-
#include <linux/ratelimit.h>
23-
#include <linux/build_bug.h>
24-
#include <net/netlink.h>
25-
#include <net/genetlink.h>
2617

2718
#include "internal.h"
28-
#include "mount.h"
29-
30-
/* Family name (max GENL_NAMSIZ characters, including null terminator) */
31-
#define DEEPIN_ERR_NOTIFY_FAMILY_NAME "DEEPIN_ENOTIFY"
32-
33-
/* Define netlink message types and attributes */
34-
enum {
35-
DEEPIN_ERR_NOTIFY_ATTR_UNSPEC,
36-
DEEPIN_ERR_NOTIFY_ATTR_FILENAME, /* Filename */
37-
DEEPIN_ERR_NOTIFY_ATTR_PID, /* Process ID */
38-
DEEPIN_ERR_NOTIFY_ATTR_COMM, /* Process Name */
39-
DEEPIN_ERR_NOTIFY_ATTR_FUNC_NAME, /* Function Name */
40-
__DEEPIN_ERR_NOTIFY_ATTR_MAX,
41-
};
42-
43-
#define DEEPIN_ERR_NOTIFY_ATTR_MAX (__DEEPIN_ERR_NOTIFY_ATTR_MAX - 1)
44-
45-
enum {
46-
DEEPIN_ERR_NOTIFY_CMD_UNSPEC,
47-
DEEPIN_ERR_NOTIFY_CMD_NOTIFY, /* Error Notify Command */
48-
__DEEPIN_ERR_NOTIFY_CMD_MAX,
49-
};
50-
51-
#define DEEPIN_ERR_NOTIFY_CMD_MAX (__DEEPIN_ERR_NOTIFY_CMD_MAX - 1)
52-
53-
/* Track deepin error notification initialization status */
54-
static bool deepin_err_notify_initialized __read_mostly;
5519

5620
/* Runtime control variable for deepin error notification */
5721
static int deepin_err_notify_enable __read_mostly = 0;
5822

5923
int deepin_err_notify_enabled(void)
6024
{
61-
return deepin_err_notify_initialized && deepin_err_notify_enable;
25+
return deepin_err_notify_enable;
6226
}
6327

28+
/* Rate limiting: allow 100 calls per 5 seconds */
29+
static DEFINE_RATELIMIT_STATE(deepin_ro_fs_err_ratelimit,
30+
5 * HZ, /* 5 seconds interval */
31+
100); /* 100 calls per interval */
32+
6433
/* Check if overlay filesystem is mounted on /usr and send read only error notification */
6534
void deepin_check_and_notify_ro_fs_err(const struct path *path,
6635
const char *func_name)
6736
{
6837
char *path_buf = NULL;
69-
char *full_path = "";
70-
/* Rate limiting: allow 100 calls per 5 seconds */
71-
static DEFINE_RATELIMIT_STATE(deepin_ro_fs_err_ratelimit,
72-
5 * HZ, /* 5 seconds interval */
73-
100); /* 100 calls per interval */
74-
75-
/* Check rate limit before proceeding */
76-
if (!__ratelimit(&deepin_ro_fs_err_ratelimit))
77-
return;
38+
const char *filename = "";
7839

79-
/* Early return if path or path->mnt is invalid */
80-
if (!path || !path->mnt || !path->mnt->mnt_sb)
40+
/* Early return if path is invalid or filesystem doesn't implement the callback */
41+
if (!path || !path->mnt || !path->mnt->mnt_sb ||
42+
!path->mnt->mnt_sb->s_op ||
43+
!path->mnt->mnt_sb->s_op->deepin_notify_error)
8144
return;
8245

83-
/* Use filesystem callback to decide if notification should be sent.
84-
* If filesystem implements the callback, use it.
85-
*/
86-
if (path->mnt->mnt_sb->s_op &&
87-
path->mnt->mnt_sb->s_op->deepin_should_notify_error) {
88-
if (!path->mnt->mnt_sb->s_op->deepin_should_notify_error(path->mnt->mnt_sb))
89-
return;
90-
} else {
91-
/* If filesystem does not implement the callback, return immediately. */
46+
/* Check rate limit before proceeding */
47+
if (!__ratelimit(&deepin_ro_fs_err_ratelimit))
9248
return;
93-
}
9449

95-
/* Attempt to get the full path.
96-
* Dynamic allocation is used to avoid excessive frame size.
97-
*/
50+
/* Convert path to filename string */
9851
if (path->dentry) {
9952
path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
10053
if (path_buf) {
101-
char *p = NULL;
102-
103-
p = d_path(path, path_buf, PATH_MAX);
54+
char *p = d_path(path, path_buf, PATH_MAX);
10455
if (!IS_ERR(p))
105-
full_path = p;
56+
filename = p;
10657
}
10758
}
10859

109-
deepin_send_ro_fs_err_notification(full_path, func_name);
110-
60+
/* Use filesystem callback to handle error notification */
61+
path->mnt->mnt_sb->s_op->deepin_notify_error(
62+
path->mnt->mnt_sb, &filename, 1, func_name);
11163
kfree(path_buf);
11264
}
11365

114-
/* Define multicast group */
115-
static const struct genl_multicast_group deepin_err_notify_nl_mcgrps[] = {
116-
{
117-
.name = "ro_fs_events",
118-
},
119-
};
66+
/* Check multiple paths and send read-only error notification */
67+
void deepin_check_and_notify_ro_fs_err_paths(const struct path *path,
68+
const struct path *path_new,
69+
const char *func_name)
70+
{
71+
char *path_bufs[2] = { NULL, NULL };
72+
const char *filenames[2] = { "", "" };
73+
int filename_count = 0;
74+
const struct super_operations *s_op = NULL;
75+
struct super_block *sb = NULL;
76+
const struct path *paths[2] = { path, path_new };
77+
int i;
78+
79+
/* First pass: find a filesystem that implements deepin_notify_error
80+
* Check both paths and use the first one that has the callback
81+
*/
82+
for (i = 0; i < 2; i++) {
83+
if (!paths[i] || !paths[i]->mnt || !paths[i]->mnt->mnt_sb)
84+
continue;
12085

121-
/* Define Generic Netlink family */
122-
static struct genl_family deepin_err_notify_genl_family __ro_after_init = {
123-
.module = THIS_MODULE,
124-
.hdrsize = 0,
125-
.name = DEEPIN_ERR_NOTIFY_FAMILY_NAME,
126-
.version = 1,
127-
.maxattr = DEEPIN_ERR_NOTIFY_ATTR_MAX,
128-
.mcgrps = deepin_err_notify_nl_mcgrps,
129-
.n_mcgrps = ARRAY_SIZE(deepin_err_notify_nl_mcgrps),
130-
};
86+
sb = paths[i]->mnt->mnt_sb;
87+
s_op = sb->s_op;
13188

132-
/* Send read only filesystem error notification */
133-
void deepin_send_ro_fs_err_notification(const char *filename,
134-
const char *func_name)
135-
{
136-
pid_t pid = 0;
137-
const char *comm = NULL;
138-
int msg_size;
139-
struct sk_buff *skb = NULL;
140-
void *msg_head = NULL;
141-
int error;
142-
143-
pid = current->pid;
144-
comm = current->comm;
145-
146-
msg_size = nla_total_size(strlen(filename) + 1) +
147-
nla_total_size(sizeof(u32)) +
148-
nla_total_size(strlen(comm) + 1) +
149-
nla_total_size(strlen(func_name) + 1);
150-
151-
/* Use GFP_NOFS to avoid recursion in file system operations. */
152-
skb = genlmsg_new(msg_size, GFP_NOFS);
153-
if (!skb) {
154-
pr_err("deepin_err_notify: Failed to allocate netlink message\n");
155-
return;
156-
}
89+
if (s_op && s_op->deepin_notify_error) {
90+
/* Found a filesystem with the callback */
91+
break;
92+
}
15793

158-
msg_head = genlmsg_put(skb, 0, 0, &deepin_err_notify_genl_family, 0,
159-
DEEPIN_ERR_NOTIFY_CMD_NOTIFY);
160-
if (!msg_head) {
161-
pr_err("deepin_err_notify: Failed to put netlink header\n");
162-
goto err_out;
94+
/* Reset for next iteration */
95+
sb = NULL;
96+
s_op = NULL;
16397
}
16498

165-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_FILENAME, filename);
166-
if (error)
167-
goto attr_err_out;
168-
169-
error = nla_put_u32(skb, DEEPIN_ERR_NOTIFY_ATTR_PID, pid);
170-
if (error)
171-
goto attr_err_out;
99+
/* Early return if no filesystem has the callback */
100+
if (!s_op || !s_op->deepin_notify_error)
101+
return;
172102

173-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_COMM, comm);
174-
if (error)
175-
goto attr_err_out;
103+
/* Check rate limit before proceeding */
104+
if (!__ratelimit(&deepin_ro_fs_err_ratelimit))
105+
return;
176106

177-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_FUNC_NAME,
178-
func_name);
179-
if (error)
180-
goto attr_err_out;
107+
/* Second pass: collect all valid filenames from both paths
108+
* Only allocate memory now that we know we'll use it
109+
*/
110+
for (i = 0; i < 2; i++) {
111+
if (!paths[i] || !paths[i]->mnt || !paths[i]->mnt->mnt_sb || !paths[i]->dentry)
112+
continue;
181113

182-
genlmsg_end(skb, msg_head);
114+
path_bufs[i] = kmalloc(PATH_MAX, GFP_KERNEL);
115+
if (path_bufs[i]) {
116+
char *p = d_path(paths[i], path_bufs[i], PATH_MAX);
117+
if (!IS_ERR(p))
118+
filenames[filename_count++] = p;
119+
}
120+
}
183121

184-
/* Send multicast message. */
185-
genlmsg_multicast(&deepin_err_notify_genl_family, skb, 0, 0, GFP_NOFS);
186-
return;
122+
/* Call the callback with collected filenames */
123+
if (filename_count == 2) {
124+
s_op->deepin_notify_error(sb, filenames, filename_count,
125+
func_name);
126+
}
187127

188-
attr_err_out:
189-
pr_err("deepin_err_notify: Failed to add netlink attributes\n");
190-
err_out:
191-
kfree_skb(skb);
128+
/* Free allocated buffers */
129+
for (i = 0; i < 2; i++)
130+
kfree(path_bufs[i]);
192131
}
193132

194133
/* sysctl table and initialization */
@@ -216,27 +155,11 @@ static void __init deepin_err_notify_sysctl_init(void)
216155
/* Deepin error notify initialization */
217156
static int __init deepin_err_notify_init(void)
218157
{
219-
int error;
220-
221-
/* Compile-time check for family name length */
222-
BUILD_BUG_ON(sizeof(DEEPIN_ERR_NOTIFY_FAMILY_NAME) > GENL_NAMSIZ);
223-
224-
error = genl_register_family(&deepin_err_notify_genl_family);
225-
if (error) {
226-
pr_err("deepin_err_notify: Failed to register Generic Netlink family: %d\n",
227-
error);
228-
return error;
229-
}
230-
231-
/* Set initialization success flag */
232-
deepin_err_notify_initialized = true;
233-
234158
/* Initialize sysctl interface */
235159
deepin_err_notify_sysctl_init();
236-
237-
pr_info("deepin_err_notify: Generic Netlink family registered successfully\n");
238160
return 0;
239161
}
240162

241163
/* Use fs_initcall to ensure initialization before file system operations */
242164
fs_initcall(deepin_err_notify_init);
165+

fs/internal.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ int deepin_get_path_for_err_notify(int dfd, struct filename *name, struct path *
6969
*/
7070
int deepin_err_notify_enabled(void);
7171
void deepin_check_and_notify_ro_fs_err(const struct path *path, const char *func_name);
72-
void deepin_send_ro_fs_err_notification(const char *filename, const char *func_name);
72+
void deepin_check_and_notify_ro_fs_err_paths(const struct path *path, const struct path *path_new, const char *func_name);
73+
74+
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
75+
/* Check if error is EROFS and notification is enabled */
76+
#define deepin_should_notify_ro_fs_err(error) \
77+
unlikely((error) == -EROFS && deepin_err_notify_enabled())
78+
#else
79+
#define deepin_should_notify_ro_fs_err(error) 0
80+
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
7381

7482
/*
7583
* namespace.c

fs/ioctl.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,10 +903,8 @@ SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
903903
if (error == -ENOIOCTLCMD)
904904
error = vfs_ioctl(f.file, cmd, arg);
905905

906-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
907-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled()))
906+
if (deepin_should_notify_ro_fs_err(error))
908907
deepin_check_and_notify_ro_fs_err(&f.file->f_path, "ioctl");
909-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
910908

911909
out:
912910
fdput(f);

0 commit comments

Comments
 (0)