Skip to content

Commit 04001ca

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: #1268 Signed-off-by: electricface <[email protected]>
1 parent 935caa3 commit 04001ca

File tree

13 files changed

+356
-242
lines changed

13 files changed

+356
-242
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5791,6 +5791,8 @@ DEEPIN ERR NOTIFY
57915791
M: "electricface" <[email protected]>
57925792
S: Maintained
57935793
F: fs/deepin_err_notify.c
5794+
F: fs/overlayfs/deepin_ovl_err_notify.c
5795+
F: fs/overlayfs/deepin_ovl_err_notify.h
57945796

57955797
DEEPIN KABI-HELPERS
57965798
M: "Lugang He" <[email protected]>

fs/deepin_err_notify.c

Lines changed: 45 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,194 +1,86 @@
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

6428
/* Check if overlay filesystem is mounted on /usr and send read only error notification */
6529
void deepin_check_and_notify_ro_fs_err(const struct path *path,
6630
const char *func_name)
6731
{
68-
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;
78-
79-
/* Early return if path or path->mnt is invalid */
80-
if (!path || !path->mnt || !path->mnt->mnt_sb)
81-
return;
82-
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. */
32+
/* Early return if path is invalid or filesystem doesn't implement the callback */
33+
if (!path || !path->mnt || !path->mnt->mnt_sb ||
34+
!path->mnt->mnt_sb->s_op ||
35+
!path->mnt->mnt_sb->s_op->deepin_notify_error)
9236
return;
93-
}
9437

95-
/* Attempt to get the full path.
96-
* Dynamic allocation is used to avoid excessive frame size.
38+
/* Use filesystem callback to handle error notification
39+
* Pass the path directly - no conversion to string needed
9740
*/
98-
if (path->dentry) {
99-
path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
100-
if (path_buf) {
101-
char *p = NULL;
102-
103-
p = d_path(path, path_buf, PATH_MAX);
104-
if (!IS_ERR(p))
105-
full_path = p;
106-
}
107-
}
108-
109-
deepin_send_ro_fs_err_notification(full_path, func_name);
110-
111-
kfree(path_buf);
41+
path->mnt->mnt_sb->s_op->deepin_notify_error(
42+
path->mnt->mnt_sb, &path, 1, func_name);
11243
}
11344

114-
/* Define multicast group */
115-
static const struct genl_multicast_group deepin_err_notify_nl_mcgrps[] = {
116-
{
117-
.name = "ro_fs_events",
118-
},
119-
};
120-
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-
};
131-
132-
/* Send read only filesystem error notification */
133-
void deepin_send_ro_fs_err_notification(const char *filename,
134-
const char *func_name)
45+
/* Check multiple paths and send read-only error notification */
46+
void deepin_check_and_notify_ro_fs_err_paths(const struct path *path,
47+
const struct path *path_new,
48+
const char *func_name)
13549
{
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-
}
157-
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;
163-
}
164-
165-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_FILENAME, filename);
166-
if (error)
167-
goto attr_err_out;
50+
const struct super_operations *s_op = NULL;
51+
struct super_block *sb = NULL;
52+
const struct path *paths[2] = { path, path_new };
53+
int i;
16854

169-
error = nla_put_u32(skb, DEEPIN_ERR_NOTIFY_ATTR_PID, pid);
170-
if (error)
171-
goto attr_err_out;
55+
/* First pass: find a filesystem that implements deepin_notify_error
56+
* Check both paths and use the first one that has the callback
57+
*/
58+
for (i = 0; i < 2; i++) {
59+
if (!paths[i] || !paths[i]->mnt || !paths[i]->mnt->mnt_sb ||
60+
!paths[i]->dentry)
61+
continue;
17262

173-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_COMM, comm);
174-
if (error)
175-
goto attr_err_out;
63+
sb = paths[i]->mnt->mnt_sb;
64+
s_op = sb->s_op;
17665

177-
error = nla_put_string(skb, DEEPIN_ERR_NOTIFY_ATTR_FUNC_NAME,
178-
func_name);
179-
if (error)
180-
goto attr_err_out;
66+
if (s_op && s_op->deepin_notify_error) {
67+
/* Found a filesystem with the callback */
68+
break;
69+
}
18170

182-
genlmsg_end(skb, msg_head);
71+
/* Reset for next iteration */
72+
sb = NULL;
73+
s_op = NULL;
74+
}
18375

184-
/* Send multicast message. */
185-
genlmsg_multicast(&deepin_err_notify_genl_family, skb, 0, 0, GFP_NOFS);
186-
return;
76+
/* Early return if no filesystem has the callback */
77+
if (!s_op || !s_op->deepin_notify_error)
78+
return;
18779

188-
attr_err_out:
189-
pr_err("deepin_err_notify: Failed to add netlink attributes\n");
190-
err_out:
191-
kfree_skb(skb);
80+
/* Call the callback with both paths directly - no string conversion needed
81+
* Both paths are valid (already checked in first pass)
82+
*/
83+
s_op->deepin_notify_error(sb, paths, 2, func_name);
19284
}
19385

19486
/* sysctl table and initialization */
@@ -216,27 +108,11 @@ static void __init deepin_err_notify_sysctl_init(void)
216108
/* Deepin error notify initialization */
217109
static int __init deepin_err_notify_init(void)
218110
{
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-
234111
/* Initialize sysctl interface */
235112
deepin_err_notify_sysctl_init();
236-
237-
pr_info("deepin_err_notify: Generic Netlink family registered successfully\n");
238113
return 0;
239114
}
240115

241116
/* Use fs_initcall to ensure initialization before file system operations */
242117
fs_initcall(deepin_err_notify_init);
118+

fs/internal.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,19 @@ int deepin_get_path_for_err_notify(int dfd, struct filename *name, struct path *
6868
* deepin_err_notify.c
6969
*/
7070
int deepin_err_notify_enabled(void);
71-
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);
71+
void deepin_check_and_notify_ro_fs_err(const struct path *path,
72+
const char *func_name);
73+
void deepin_check_and_notify_ro_fs_err_paths(const struct path *path,
74+
const struct path *path_new,
75+
const char *func_name);
76+
77+
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
78+
/* Check if error is EROFS and notification is enabled */
79+
#define deepin_should_notify_ro_fs_err(error) \
80+
unlikely((error) == -EROFS && deepin_err_notify_enabled())
81+
#else
82+
#define deepin_should_notify_ro_fs_err(error) 0
83+
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
7384

7485
/*
7586
* 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)