Skip to content

Commit cdfe7d0

Browse files
committed
fs: Enhanced error notification mechanism for read-only filesystems
- Added handling for the two paths that need to be reported in the rename system call. - Introduced a new macro `deepin_should_notify_ro_fs_err` to simplify error-checking code. - Collect more detailed information when an error occurs. - Replaced the `/proc/sys/fs/deepin-err-notify-enable` file with multiple netlink commands. - Reverted modifications to overlayfs; the `deepin_err_notify` mount option is no longer available. Link: #1268 Signed-off-by: electricface <[email protected]>
1 parent 4048893 commit cdfe7d0

File tree

10 files changed

+762
-289
lines changed

10 files changed

+762
-289
lines changed

fs/deepin_err_notify.c

Lines changed: 582 additions & 114 deletions
Large diffs are not rendered by default.

fs/internal.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,35 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode);
6262
int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
6363
int do_linkat(int olddfd, struct filename *old, int newdfd,
6464
struct filename *new, int flags);
65-
int deepin_get_path_for_err_notify(int dfd, struct filename *name, struct path *result_path);
65+
struct deepin_path_last {
66+
struct path path;
67+
const char *last;
68+
};
69+
70+
int deepin_lookup_path_or_parent(int dfd, struct filename *name,
71+
unsigned int flags,
72+
struct deepin_path_last *result_path_last);
6673

6774
/*
6875
* deepin_err_notify.c
6976
*/
7077
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);
78+
int deepin_err_notify_should_send(void);
79+
void deepin_check_and_notify_ro_fs_err(const struct deepin_path_last *path_last,
80+
const char *func_name);
81+
void deepin_notify_rename_ro_fs_err(const struct qstr *old_last,
82+
const struct qstr *new_last,
83+
const struct path *old_path,
84+
const struct path *new_path);
85+
void deepin_put_path_last(struct deepin_path_last *path_last);
86+
87+
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
88+
/* Check if error is EROFS and notification should be sent */
89+
#define deepin_should_notify_ro_fs_err(error) \
90+
unlikely((error) == -EROFS && deepin_err_notify_should_send())
91+
#else
92+
#define deepin_should_notify_ro_fs_err(error) 0
93+
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
7394

7495
/*
7596
* namespace.c

fs/ioctl.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -903,10 +903,13 @@ 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()))
908-
deepin_check_and_notify_ro_fs_err(&f.file->f_path, "ioctl");
909-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
906+
if (deepin_should_notify_ro_fs_err(error)) {
907+
struct deepin_path_last tmp_path_last = {
908+
.path = f.file->f_path,
909+
.last = NULL
910+
};
911+
deepin_check_and_notify_ro_fs_err(&tmp_path_last, "ioctl");
912+
}
910913

911914
out:
912915
fdput(f);

fs/namei.c

Lines changed: 101 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,19 +4073,14 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
40734073
goto retry;
40744074
}
40754075
out1:
4076-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4077-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4078-
struct path file_path;
4079-
int get_path_err;
4080-
4081-
get_path_err =
4082-
deepin_get_path_for_err_notify(dfd, name, &file_path);
4083-
if (!get_path_err) {
4084-
deepin_check_and_notify_ro_fs_err(&file_path, "mknod");
4085-
path_put(&file_path);
4076+
if (deepin_should_notify_ro_fs_err(error)) {
4077+
struct deepin_path_last path_last;
4078+
4079+
if (!deepin_lookup_path_or_parent(dfd, name, lookup_flags, &path_last)) {
4080+
deepin_check_and_notify_ro_fs_err(&path_last, "mknod");
4081+
deepin_put_path_last(&path_last);
40864082
}
40874083
}
4088-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
40894084
putname(name);
40904085
return error;
40914086
}
@@ -4169,19 +4164,14 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode)
41694164
goto retry;
41704165
}
41714166
out_putname:
4172-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4173-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4174-
struct path file_path;
4175-
int get_path_err;
4176-
4177-
get_path_err =
4178-
deepin_get_path_for_err_notify(dfd, name, &file_path);
4179-
if (!get_path_err) {
4180-
deepin_check_and_notify_ro_fs_err(&file_path, "mkdir");
4181-
path_put(&file_path);
4167+
if (deepin_should_notify_ro_fs_err(error)) {
4168+
struct deepin_path_last path_last;
4169+
4170+
if (!deepin_lookup_path_or_parent(dfd, name, lookup_flags, &path_last)) {
4171+
deepin_check_and_notify_ro_fs_err(&path_last, "mkdir");
4172+
deepin_put_path_last(&path_last);
41824173
}
41834174
}
4184-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
41854175
putname(name);
41864176
return error;
41874177
}
@@ -4299,21 +4289,18 @@ int do_rmdir(int dfd, struct filename *name)
42994289
inode_unlock(path.dentry->d_inode);
43004290
mnt_drop_write(path.mnt);
43014291
exit2:
4302-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4303-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4304-
dentry = lookup_one_qstr_excl(&last, path.dentry, 0);
4305-
if (!IS_ERR(dentry)) {
4306-
if (d_is_positive(dentry)) {
4307-
// dentry is positive, so we can get the path
4308-
struct path file_path = { .mnt = path.mnt,
4309-
.dentry = dentry };
4310-
deepin_check_and_notify_ro_fs_err(&file_path,
4292+
if (deepin_should_notify_ro_fs_err(error)) {
4293+
struct deepin_path_last path_last;
4294+
4295+
if (!deepin_lookup_path_or_parent(dfd, name, lookup_flags, &path_last)) {
4296+
if (!path_last.last) {
4297+
// File exists, notify error
4298+
deepin_check_and_notify_ro_fs_err(&path_last,
43114299
"rmdir");
43124300
}
4313-
dput(dentry);
4301+
deepin_put_path_last(&path_last);
43144302
}
43154303
}
4316-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
43174304
path_put(&path);
43184305
if (retry_estale(error, lookup_flags)) {
43194306
lookup_flags |= LOOKUP_REVAL;
@@ -4459,21 +4446,18 @@ int do_unlinkat(int dfd, struct filename *name)
44594446
}
44604447
mnt_drop_write(path.mnt);
44614448
exit2:
4462-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4463-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4464-
dentry = lookup_one_qstr_excl(&last, path.dentry, 0);
4465-
if (!IS_ERR(dentry)) {
4466-
if (d_is_positive(dentry)) {
4467-
// dentry is positive, so we can get the path
4468-
struct path file_path = { .mnt = path.mnt,
4469-
.dentry = dentry };
4470-
deepin_check_and_notify_ro_fs_err(&file_path,
4449+
if (deepin_should_notify_ro_fs_err(error)) {
4450+
struct deepin_path_last path_last;
4451+
4452+
if (!deepin_lookup_path_or_parent(dfd, name, lookup_flags, &path_last)) {
4453+
if (!path_last.last) {
4454+
// File exists, notify error
4455+
deepin_check_and_notify_ro_fs_err(&path_last,
44714456
"unlink");
44724457
}
4473-
dput(dentry);
4458+
deepin_put_path_last(&path_last);
44744459
}
44754460
}
4476-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
44774461
path_put(&path);
44784462
if (retry_estale(error, lookup_flags)) {
44794463
lookup_flags |= LOOKUP_REVAL;
@@ -4574,20 +4558,15 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
45744558
goto retry;
45754559
}
45764560
out_putnames:
4577-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4578-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4579-
struct path file_path;
4580-
int get_path_err;
4581-
4582-
get_path_err =
4583-
deepin_get_path_for_err_notify(newdfd, to, &file_path);
4584-
if (!get_path_err) {
4585-
deepin_check_and_notify_ro_fs_err(&file_path,
4561+
if (deepin_should_notify_ro_fs_err(error)) {
4562+
struct deepin_path_last path_last;
4563+
4564+
if (!deepin_lookup_path_or_parent(newdfd, to, lookup_flags, &path_last)) {
4565+
deepin_check_and_notify_ro_fs_err(&path_last,
45864566
"symlink");
4587-
path_put(&file_path);
4567+
deepin_put_path_last(&path_last);
45884568
}
45894569
}
4590-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
45914570
putname(to);
45924571
putname(from);
45934572
return error;
@@ -4766,19 +4745,14 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
47664745
goto retry;
47674746
}
47684747
out_putpath:
4769-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
4770-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
4771-
struct path file_path;
4772-
int get_path_err;
4773-
4774-
get_path_err =
4775-
deepin_get_path_for_err_notify(newdfd, new, &file_path);
4776-
if (!get_path_err) {
4777-
deepin_check_and_notify_ro_fs_err(&file_path, "link");
4778-
path_put(&file_path);
4748+
if (deepin_should_notify_ro_fs_err(error)) {
4749+
struct deepin_path_last path_last;
4750+
4751+
if (!deepin_lookup_path_or_parent(newdfd, new, how, &path_last)) {
4752+
deepin_check_and_notify_ro_fs_err(&path_last, "link");
4753+
deepin_put_path_last(&path_last);
47794754
}
47804755
}
4781-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
47824756
path_put(&old_path);
47834757
out_putnames:
47844758
putname(old);
@@ -5133,22 +5107,8 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
51335107
}
51345108
mnt_drop_write(old_path.mnt);
51355109
exit2:
5136-
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
5137-
if (unlikely((error == -EROFS) && deepin_err_notify_enabled())) {
5138-
old_dentry =
5139-
lookup_one_qstr_excl(&old_last, old_path.dentry, 0);
5140-
if (!IS_ERR(old_dentry)) {
5141-
if (d_is_positive(old_dentry)) {
5142-
struct path file_path = { .mnt = old_path.mnt,
5143-
.dentry =
5144-
old_dentry };
5145-
deepin_check_and_notify_ro_fs_err(&file_path,
5146-
"rename");
5147-
}
5148-
dput(old_dentry);
5149-
}
5150-
}
5151-
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
5110+
if (deepin_should_notify_ro_fs_err(error))
5111+
deepin_notify_rename_ro_fs_err(&old_last, &new_last, &old_path, &new_path);
51525112
if (retry_estale(error, lookup_flags))
51535113
should_retry = true;
51545114
path_put(&new_path);
@@ -5368,37 +5328,76 @@ const struct inode_operations page_symlink_inode_operations = {
53685328
EXPORT_SYMBOL(page_symlink_inode_operations);
53695329

53705330
#ifdef CONFIG_DEEPIN_ERR_NOTIFY
5371-
int deepin_get_path_for_err_notify(int dfd, struct filename *name,
5372-
struct path *result_path)
5331+
/**
5332+
* deepin_lookup_path_or_parent - Prepare path info for read-only FS error notification
5333+
* @dfd: Directory file descriptor used as lookup base
5334+
* @name: Filename to look up (struct filename)
5335+
* @flags: Lookup flags (e.g., LOOKUP_DIRECTORY, LOOKUP_FOLLOW)
5336+
* @result_path_last: Output structure carrying the resolved parent path and
5337+
* optionally the last component string
5338+
*
5339+
* Memory/Lifetime management:
5340+
* - result_path_last->path:
5341+
* The path returned by filename_lookup() or filename_parentat() already
5342+
* holds a reference count. You MUST release it after use. Preferred:
5343+
* deepin_put_path_last(&pl), which will call path_put() for you.
5344+
* Alternatively, call path_put() manually if you manage the string separately.
5345+
*
5346+
* - result_path_last->last:
5347+
* In the -ENOENT (parent found) case, the last component string is duplicated
5348+
* via kstrdup() and MUST be freed with kfree(). deepin_put_path_last(&pl)
5349+
* will free it for you. If the full path was resolved, this field is set
5350+
* to NULL and no extra string free is needed.
5351+
*
5352+
* Recommended usage pattern:
5353+
* struct deepin_path_last pl;
5354+
* if (!deepin_lookup_path_or_parent(dfd, name, lookup_flags, &pl)) {
5355+
* deepin_check_and_notify_ro_fs_err(&pl, "op");
5356+
* deepin_put_path_last(&pl); // releases path and frees pl.last if allocated
5357+
* }
5358+
*
5359+
* Return: 0 on success, negative errno on failure.
5360+
*/
5361+
int deepin_lookup_path_or_parent(int dfd, struct filename *name,
5362+
unsigned int flags,
5363+
struct deepin_path_last *result_path_last)
53735364
{
5365+
struct path result_path;
5366+
struct path parent;
53745367
struct qstr last;
5375-
struct path parent_path;
53765368
int type;
5377-
struct dentry *dentry;
53785369
int error;
53795370

5380-
error = filename_parentat(dfd, name, 0, &parent_path, &last, &type);
5371+
error = filename_lookup(dfd, name, flags, &result_path, NULL);
5372+
if (error == -ENOENT) {
5373+
error = filename_parentat(dfd, name, flags, &parent, &last, &type);
5374+
if (error)
5375+
return error;
5376+
if (unlikely(type != LAST_NORM)) {
5377+
path_put(&parent);
5378+
return -EINVAL;
5379+
}
5380+
/* Duplicate the filename string to avoid dangling pointer */
5381+
result_path_last->last = kstrdup((const char *)last.name, GFP_KERNEL);
5382+
if (!result_path_last->last) {
5383+
path_put(&parent);
5384+
return -ENOMEM;
5385+
}
5386+
result_path_last->path = parent;
5387+
return 0;
5388+
}
5389+
53815390
if (error)
53825391
return error;
53835392

5384-
dentry = lookup_one_qstr_excl(&last, parent_path.dentry, 0);
5385-
if (!IS_ERR(dentry)) {
5386-
result_path->mnt = parent_path.mnt;
5387-
result_path->dentry = dentry;
5388-
path_get(result_path); // Increment reference count
5389-
dput(dentry);
5390-
} else {
5391-
// If the file does not exist, use the parent directory
5392-
*result_path = parent_path;
5393-
path_get(result_path);
5394-
}
5395-
5396-
path_put(&parent_path);
5393+
result_path_last->last = NULL;
5394+
result_path_last->path = result_path;
53975395
return 0;
53985396
}
53995397
#else
5400-
int deepin_get_path_for_err_notify(int dfd, struct filename *name,
5401-
struct path *result_path)
5398+
int deepin_lookup_path_or_parent(int dfd, struct filename *name,
5399+
unsigned int flags,
5400+
struct deepin_path_last *result_path_last)
54025401
{
54035402
return -EOPNOTSUPP;
54045403
}

0 commit comments

Comments
 (0)