Skip to content

Commit 27bcd26

Browse files
committed
fs: Enhance read-only filesystem error notification mechanism
This update introduces a new function, deepin_check_and_notify_ro_fs_err_paths, which allows for error notifications to be sent for multiple paths during filesystem operations. The existing error notification system has been refactored to improve clarity and efficiency, including the integration of a notifier chain for OverlayFS errors. Key changes: - Added support for notifying about read-only filesystem errors during rename operations. - Refactored error notification handling to utilize filesystem callbacks for improved modularity. - Introduced a new header and source file for OverlayFS error notifications, allowing external modules to register for error notifications. This enhancement aims to provide better error handling and notification capabilities for read-only filesystem operations.
1 parent 935caa3 commit 27bcd26

File tree

12 files changed

+355
-222
lines changed

12 files changed

+355
-222
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,17 @@ 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_check_and_notify_ro_fs_err_paths(const struct path *path, const struct path *path_new, const char *func_name);
7273
void deepin_send_ro_fs_err_notification(const char *filename, const char *func_name);
7374

75+
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
76+
/* Check if error is EROFS and notification is enabled */
77+
#define deepin_should_notify_ro_fs_err(error) \
78+
unlikely((error) == -EROFS && deepin_err_notify_enabled())
79+
#else
80+
#define deepin_should_notify_ro_fs_err(error) 0
81+
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
82+
7483
/*
7584
* namespace.c
7685
*/

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)